I'm trying to understand the different use cases. and the difference between the 2 thread uses.
This is a great tutorial I have read which explains boost::thread_group.
and here is a code I'm using:
boost::threadpool::pool s_ThreadPool(GetCoreCount());
CFilterTask task(pFilter, // filter to run
boost::bind(&CFilterManagerThread::OnCompleteTask, this, _1, _2) // OnComplete sync callback // _1 will be filter name // _2 will be error code
);
// schedule the new task - runs on the threadpool
s_ThreadPool.schedule(task);
this is the destructor:
s_ThreadPool.wait(0);
can you please explain?
boost::thread_group is a convenience class for performing thread management operations on a collection of threads. For example, instead of having to iterate over std::vector<boost::thread>, invoking join() on each thread, the thread_group provides a convenient join_all() member function.
With boost::thread, regardless of it being managed by boost::thread_group, the lifetime of the thread is often dependent on the work in which the thread is doing. For example, if a thread is created to perform a computationally expensive calculation, then the thread can exit once the result has been calculated. If the work is short-lived, then the overhead of creating and destroying threads can affect performance.
On the other hand, a threadpool is a pattern, where a number of threads services a number of task/work. The lifetime of the thread is not directly associated with the lifetime of the task. To continue with the previous example, the application would schedule the computationally expensive calculation to run within the thread pool. The work will be queued within the threadpool, and one of the threadpool's threads will be selected to perform the work. Once the calculation has completed, the thread goes back to waiting for more work to be scheduled with the threadpool.
As shown in this threadpool example, a threadpool can be implemented with boost::thread_group to manage lifetime of threads, and boost::asio::io_service for task/work dispatching.
Related
Lines from Anthony William book:
std::launch::deferred indicates that the function call is to be
deferred until either wait() or get() is called on the future.
X baz(X&);
auto f7 = std::async(std::launch::deferred, baz, std::ref(x)); //run in wait() or get()
//...
f7.wait(); //invoke deferred function
What could be the benefits or differences of this code over a direct call (baz(ref(x)) )?
In other words, what's the point of having future here?
Suppose you have a thread pool.
The thread pool owns a certain number of threads. Say 10.
When you add tasks, they return a future, and they queue into the pool.
Threads in the pool wake up, grab a task, work on it.
What happens when you have 10 tasks in that pool waiting on a task later in the queue? Well, a deadlock.
Now, what if we return a deferred future from this pool.
When you wait on this deferred future it wakes up, checks if the task is done. If so, it finishes and returns.
Next, if the tasks is in the queue and not yet started, it steals the work from the queue and runs it right there, and returns.
Finally, if it is being run by the queue but not finished, it does something more complex. (the simplest version which usually works is that it blocks on the task, but that doesn't solve some pathological cases).
In any case, now if a task in the queue sleeps waits for another task in the queue to complete that isn't queue'd yet, we still get forward progress.
Another use of this is less arcane. Suppose we have some lazy values.
Instead of calculating them, we store shared futures with the calcuation steps in them. Now anyone who needs them just does a .get(). If the value has already been calculated, we get the value; otherwise, we calculate it, then get it.
Later, we add in a system to do some work on idle or in another thread. These replace said deferred lazy futures in some cases, but not in others.
I think, the main benefit is that it might be executed in a different thread - the one which actually reads the future. This allows to transfer 'units of work' between threads - i.e. thread 1 creates the future, while thread 2 calls wait on it.
in my point of view. I read effective modern c++ rule 35
Compared to thread-based programming, a task-based design spares you the travails
of manual thread management
it means std::launch::deferred is a worse case when the OS have no ability to allocate a new thread for you however, the baz function still work but it run as a deferred task instead of returning failed like pthread_create or throw exception with std::thread like this:
terminate called after throwing an instance of 'std::system_error'
what(): Resource temporarily unavailable
conclusion:
// same thread with called.
std::async(std::launch::deferred, bax,..) = baz()
// create a new thread to run baz(..) in case of OS have ability to allocate a new thread, otherwise same above
std::async(baz, ...) = std::async(std::launch::deferred| std::launch::async , baz, ...) != baz() ;
https://man7.org/linux/man-pages/man3/pthread_create.3p.html
tested at https://godbolt.org/z/hYv7TW51q
So I ran across something that seems to defeat the purpose of std::thread or at least makes it less convenient.
Say I want to spawn an std::thread to perform a task one time and don't want to worry about it again after that. I create this thread near the end of a function so the std::thread will soon go out of scope, in my case, likely while the thread is still running. This creates a problem with a couple of solutions (or at least that I know of).
I can:
A) Make the std::thread a global variable so it doesn't go out of scope.
B) Call join() on the std::thread which defeats the purpose of spawning the thread.
Are there other, hopefully better, ways to handle this kind of situation?
What you want is std::thread::detach.
It decouples the actual thread of execution and the std::thread object, allowing you to destroy it without joining the threads.
You can use std::async.
async runs the function f asynchronously (potentially in a separate thread which may be part of a thread pool) and returns a std::future that will eventually hold the result of that function call.
Since you did not mention that you need to get the result of the thread, there is no need to get the future.
As pointed out in the comments, the destructor of std::future will block in any case, so you will have to move it to some global object (and manually manage deletion of unused futures), or you can move it into the local scope of the asynchronously called function.
Other preferred option is to allow the thread to consume tasks from a task-queue. For that, split the job into task chuncks and feed to the worker thread. To avoid polling, opt for condition_variable.
std::thread([&](){
while(running) // thread loop
{
// consume tasks from queue
}
}).detach();
Lines from Anthony William book:
std::launch::deferred indicates that the function call is to be
deferred until either wait() or get() is called on the future.
X baz(X&);
auto f7 = std::async(std::launch::deferred, baz, std::ref(x)); //run in wait() or get()
//...
f7.wait(); //invoke deferred function
What could be the benefits or differences of this code over a direct call (baz(ref(x)) )?
In other words, what's the point of having future here?
Suppose you have a thread pool.
The thread pool owns a certain number of threads. Say 10.
When you add tasks, they return a future, and they queue into the pool.
Threads in the pool wake up, grab a task, work on it.
What happens when you have 10 tasks in that pool waiting on a task later in the queue? Well, a deadlock.
Now, what if we return a deferred future from this pool.
When you wait on this deferred future it wakes up, checks if the task is done. If so, it finishes and returns.
Next, if the tasks is in the queue and not yet started, it steals the work from the queue and runs it right there, and returns.
Finally, if it is being run by the queue but not finished, it does something more complex. (the simplest version which usually works is that it blocks on the task, but that doesn't solve some pathological cases).
In any case, now if a task in the queue sleeps waits for another task in the queue to complete that isn't queue'd yet, we still get forward progress.
Another use of this is less arcane. Suppose we have some lazy values.
Instead of calculating them, we store shared futures with the calcuation steps in them. Now anyone who needs them just does a .get(). If the value has already been calculated, we get the value; otherwise, we calculate it, then get it.
Later, we add in a system to do some work on idle or in another thread. These replace said deferred lazy futures in some cases, but not in others.
I think, the main benefit is that it might be executed in a different thread - the one which actually reads the future. This allows to transfer 'units of work' between threads - i.e. thread 1 creates the future, while thread 2 calls wait on it.
in my point of view. I read effective modern c++ rule 35
Compared to thread-based programming, a task-based design spares you the travails
of manual thread management
it means std::launch::deferred is a worse case when the OS have no ability to allocate a new thread for you however, the baz function still work but it run as a deferred task instead of returning failed like pthread_create or throw exception with std::thread like this:
terminate called after throwing an instance of 'std::system_error'
what(): Resource temporarily unavailable
conclusion:
// same thread with called.
std::async(std::launch::deferred, bax,..) = baz()
// create a new thread to run baz(..) in case of OS have ability to allocate a new thread, otherwise same above
std::async(baz, ...) = std::async(std::launch::deferred| std::launch::async , baz, ...) != baz() ;
https://man7.org/linux/man-pages/man3/pthread_create.3p.html
tested at https://godbolt.org/z/hYv7TW51q
I want to implement thread pool using boost::thread class.
I am able to create the threads using below line.
boost::thread Consumer_1(consume);
where consumer_1 is thread and consume is the function bound to it.
Above statement starts the thread as soon as it gets executed.
Now I just want to create the thread and do the binding run time.
I have not yet discovered the boost method to delay this binding.
Can anyone help on this?
The binding can't be done later. For principal reasons—a thread of execution has to be executing something.
What you need to do is create a function, that will take jobs, represented as boost::function, from a queue and execute them. Than run this function in one or more threads.
I am not sure there is a thread-safe queue, but you can always use a regular std::deque with boost::condition_variable for waking up the threads and boost::mutex for locking the deque.
You might want to look at Boost.Asio too. See also here.
boost::thread is not-a-thread, a new thread is created when the ftor passed to it is called and thread exits when ftor returns.
We use threadpool to minimize thread creation and destruction cost. but each thread in threadpool is also destroyed when the supplied ftor returns.
So whats the basic concept behind building a threadpool ? is there any permanent thread where I can assign ftors to that thread ?
A thread pool is just a bunch of threads that already running, and that are all running the same function. This functions basically just waits on a queue, and when there is a "function" in the queue it extracts and executes it.
Pseudo-code:
void thread_pool_function()
{
while (true)
{
wait_for_signal_that_queue_is_not_empty();
function_to_call = queue.remove_top();
unklock_queue_semaphore();
function_to_call();
}
}
create_thread(thread_pool_function);
create_thread(thread_pool_function);
create_thread(thread_pool_function);
create_thread(thread_pool_function);
In the "code" above there are now four threads, all initially waiting for something to be put in a "queue". When there is something in the queue, it extracts it, and calls it as a function.
This is probably the simplest way to implement a thread pool.
In addtion to what #Joachim posted:
One way to flow-control such a system (and one I use a lot), is to use a 'pool queue', (blocking producer-consumer queue), of tasks, created and filled at startup with a fixed number of task objects. Any thread that wants to issue a task has to get one from the pool first and tasks are returned to the pool after completion handling. This limits the number of tasks in the system and, if the pool empties, requesting threads just have to wait, blocked on the empty pool, until some 'used' tasks come back in.
This works well, provides flow-control, prevents memory-runaway and eliminates continual task create/destroy. It's also easy to periodically display/write the pool queue depth on a timer, so you can see how 'busy' your app is, (and detect any leaks:).
Edit: Also, it removes the need for any bounded queues in the system. Unbounded queues are simpler and tend to need fewer system calls.