1

I am trying to use the multithreading features in the C++11 standard library and have the following situation envisioned.

I have a parent class which maintains a queue of thread. So something like:

std::queue<MyMTObject *>  _my_threads;

The class MyMTObject contains the std::thread object. The queue has a fixed size of 5 and the class initially starts with the queue being full.

As I have jobs to process I launch threads and I remove them from the queue. What I would like is to get a notification when the job is finished along with the pointer to the MyMTObject, so that I can reinsert them into the queue and make them available again.

I have basically 2 questions:

1: Is this a sound idea? I know I have not specified specifics but broadly speaking. I will, of course, control all access to the queue with a mutex.

2: Is there a way to implement this notification mechanism without using external libraries like Qt or boost.

For duplicates, I did look on the site but could not find anything that was suitable to manage a collection of threads.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
Luca
  • 10,458
  • 24
  • 107
  • 234
  • 2
    I do not think the duplicate is correct. The question is about single thread, OP has a collection of them. – SergeyA Nov 11 '15 at 18:45
  • 3
    I agree. I think this is one of the many cases where the *answers* would be close to duplicates, but the question is not at all. – Johan Lundberg Nov 11 '15 at 18:51
  • You could pass a callback to the thread when you initialize it, and then invoke the callback just before terminating the thread. Not the most beautiful solution, but it should work. – jweyrich Nov 11 '15 at 19:10
  • 1
    Are your threads detached? – Jason Nov 11 '15 at 19:38
  • @jweyrich This seems like a reasonably low cost approach. Wanna write it as an answer? I will give it a shot. – Luca Nov 11 '15 at 19:40
  • @Jason The threads do not have to communicate with each other. – Luca Nov 11 '15 at 20:16
  • What does that have to do with being detached? – Jason Nov 11 '15 at 20:27
  • @Jason If you mean my thread is separate from the `MyMtObject`, than no. The threads needs access to data private to `MyMtObject`. I am afraid I probably do not understand what a detached thread is. – Luca Nov 11 '15 at 20:30
  • What I mean is if you've called `std::thread::detach`. – Jason Nov 11 '15 at 20:31
  • @Jason No, I have not. – Luca Nov 11 '15 at 20:32
  • 2
    You could use a custom deleter. Instead of storing the raw pointer in the queue, you use a smart pointer that reinserts into the queue on deletion. – James Nov 11 '15 at 21:15

3 Answers3

2

I'm not sure if I need to mention this, but std::thread objects can't be re-used. Generally, the only reason you keep a std::thread reference is to std::thread::join the thread. If you don't plan to join the thread later (e.g. dispatch to threads and wait for completion), it's generally advised to std::thread::detach it.

If you're trying to keep threads for a thread pool, it's probably easier to have each thread block on the std::queue and pull objects from the queue to work on. This is relatively easy to implement using a std::mutex and a std::condition_variable. It generally gives good throughput, but to get finer control over scheduling you can do things like keep a seperate std::queue for each thread.

Detaching the threads and creating a work queue also has the added benefit that it avoids redundantly requesting the operating system create new threads which adds overhead and increases overall resource usage.

Jason
  • 3,777
  • 14
  • 27
1

You could try to deploy some version of Reactor pattern I think. So, you could start one additional control thread that cleans after these workers. Now, you create a ThreadSafeQueue that will be used to communicate events from worker threads to control thread. This queue should be implemented in such a way that you can select on it and wait for any activity on the other end (some thread terminates and calls queue.push for example).

All in all I think it's quite elegant solution. I does add an overhead of an additional thread, but this thread will be mostly sleeping and waking up only once a while to clean up after the worker.

dbajgoric
  • 1,447
  • 11
  • 17
0

There is no elegant way to do this in Posix, and C++ threading model is almost a thin wrapper on Posix.

You can join a specific thread (one at a time), or you can wait on futures - again, one future at a time.

The best you can do to avoid looping is to employ a conditional variable, and make all threads singal on it (as well as indicating which one just exited by setting some sort of per-thread flag) just before they are about to exit. The 'reaper' would notice the signal and check the flags.

The issue is that this solution requires thread cooperation. But I know not of any better.

SergeyA
  • 61,605
  • 5
  • 78
  • 137