pause/resume of task - control of system load

pause/resume of task - control of system load

Hi,

I need twos features that I'm currently unable to find in TBB:

- a way to reduce (at runtime, and during a task execution) the number of threads used.
- a way to pause the execution of my tasks (or allocate 0 threads to the current task)

The idea behind that is that the user of my tool must be allowed to pause the execution if he wants to free its processor for another task. Or he may decide to only allocate 4 of its 8 cores to this task.

Because my task can take a while to end, I need to be able to do this change "in the middle of a task".

I'm currently using task_scheduler_init between the creation of task, but because it waits for the end of task to take effect, the effect can take too long.

Is there a way to do this inside TBB?

Thank you.

4 Beiträge / 0 neu
Letzter Beitrag
Nähere Informationen zur Compiler-Optimierung finden Sie in unserem Optimierungshinweis.

Create a parking task that each thread is likely to fall through (as a task).

The task is a NOP task except when a thread must be suspended. At that time the thread issues a Sleep or WaitForSingleEvent or condition variable (or you choose your own medicine).

This may require a non-TBB thread to query and modify the state variables (desired number of threads).
This parking task needs to be periodically scheduled during your normal running of the app. This task could get scheduled only when the state variable indicates an additional thread needs to be suspended. This won't provide instanteanous suspension.

Jim Dempsey

www.quickthreadprogramming.com

"Create a parking task that each thread is likely to fall through (as a task)."
Hmm... that still won't prevent one or more tasks' getting trapped on the stack in the middle of its/their execution, so you might as well keep track of the current set using task_scheduler_observer() and suspend them directly for immediate effect. I hope some more work gets done in that general area for TBB to play nice with other threading models (although that goes both ways!).

Thank for your advices.

I defined an API like that:

#ifndef TBB_PAUSE_H

#define TBB_PAUSE_H
/*

 * tbb/compat/condition_variable provides the std::unique_lock and

 * std::condition_variable of C++ 2011 in STD namespace

 */
#include "tbb/tbb.h"

#include "tbb/compat/condition_variable"
class Scheduler

{

public:

	Scheduler(unsigned m):

		max_thread_count(m), current_thread_count(0)

	{}
	void SetNumThread(int num)

	{

		std::unique_lock lock(mutex);
		int delta = num - max_thread_count;
		// Wake up sleeping threads

		if(delta > 0)

			for(int i = 0; i < delta; ++i)

				condition.notify_one();
		max_thread_count = num;

	}
private:

	friend class Pause;
	// Called when a thread starts a range

	void Begin()

	{

		std::unique_lock lock(mutex);
		while(current_thread_count >= max_thread_count)

			condition.wait(lock);
		current_thread_count++;

	}
	// At the end of a range

	void End()

	{

		std::unique_lock lock(mutex);
		current_thread_count--;
		// this test is not useful, but avoid a thread wakeup for nothing

		if(current_thread_count < max_thread_count)

			condition.notify_one();

	}
private:

	tbb::mutex mutex;

	std::condition_variable condition;
	int max_thread_count, current_thread_count;

};
// Pause object, you must create one at the beginning of your task

class Pause

{

public:

	Pause(Scheduler * const sched): scheduler(sched)

	{

		scheduler->Begin();

	}
	~Pause()

	{

		scheduler->End();

	}

private:

	Scheduler * const scheduler;

};
#endif


And it can be used like that:

#include "tbb_pause.h"

Scheduler* scheduler;

// A simple class
void mytask(const tbb::blocked_range&range)
{
// Create the pause object
Pause pause(scheduler);

for(size_t i = range.begin(); i != range.end(); ++i)
{
// Do useless work
int sum = 0;
for(unsigned int j = 0; j < 100; j++)
{
sum += j;
}
}
}

void set_pause()
{
sleep(1);
// Pause after one seconds
scheduler->SetNumThread(0);

// pause of ten seconds, resume with one threads
sleep(5);

scheduler->SetNumThread(1);
}

int main(int, char** argv)
{
Scheduler sched(8);
scheduler = &sched;

//boost::thread t(set_pause);

tbb::parallel_for(tbb::blocked_range(0, atoi(argv[1])), &mytask);
}

The idea is that any blocked_range executed by TBB can create a scoped Pause instance which will control the number of threads. I can pause/resume by setting the number of threads to zero.

I'm pretty sure this API is not recursive (IE, a task cannot create another task), but it may work for my purpose.

Thank for your help, and if you come with any random remarks about this piece of code, I'll be rather happy.

Kommentar hinterlassen

Bitte anmelden, um einen Kommentar hinzuzufügen. Sie sind noch nicht Mitglied? Jetzt teilnehmen