Reputation: 1427
How can I send an event to several running threads of my application?
For example: My main thread wants to signal all running threads that the application will exit.
I'm a little confused which of those possibilities leads to an easy and reliable solution:
condition_variable
with notify_all
from boost
CONDITION_VARIABLE
with WakeAllConditionsVariable
from WinApiCEvent
from WinApimutex
and try_lock
on the threadssignal
and slots
from boost
CriticalSection
for protection of getter/settersCould you point a beginner into the right direction and perhaps loose some words about the possiblities above I provided.
Added: - OS is Windows XP
Upvotes: 3
Views: 3800
Reputation: 15327
If you are simply testing for a simple change in state (when to exit), a condition variable is sufficient. Just make sure you find a good WinAPI example to follow: you almost certainly need test the state multiple times (unlike what your intuition may tell you).
If you intend to share tasks/events between threads, a good pattern is to use a producer-consumer pattern, based on a mutexed queue and a condition variable. A typical example is, you have one producer thread that produces jobs which are pushed onto the queue (eg write data to a different file per task). Then, you can have multiple consumer threads which will remove the task from the queue and act on them. To communicate between the threads, you can have a condition variable which will signal to the consumer threads that the mutexed queue may be empty. (Read up on condition variables to understand why I say "may" here).
As you do more and more thread programming, you will look for opportunities where mutexes are unnecessary. For example, if I have a ton of read-only data on disk and I want your threads to calculate on this data, you can read the data before spawning your threads. All your threads will then have access to this data without having to use locks, as long as they behave and do not write to the data. You will find that you implement many thread patterns with just mutexes and condition variables (part of the reason while the POSIX thread library is so small).
One last note: it's a bit out of the scope of your question, but you will also get a feel of how many threads you really need to spawn. Context-switches between threads are relatively cheap, but the costs is definitely non-zero. That means there is a point of diminishing returns when spawning more threads. Just think about it in terms of the OS: the algorithm must spend cycles to decide when to context switch in addition to actually do the switch. This cost is not zero. So another type of optimization you will find as you do more thread-programming is, when to do as much work as you can in the thread without waiting for another thread to do the work. Of course, you must strike a balance between cleanliness of your design and optimizing for speed. It's just something to think about as you design your application.
Upvotes: 2
Reputation: 208353
You have two different problems here. The first one is how to make a bit of data available to different parts of the code, so that the different threads can read it, while the second one is how to modify a bit of state in a thread safe way so that the threads can act on it.
To make a bit of data available to the different threads you can use different approaches:
exit
signal, and connect all threads on construction.exit
flag as a global variable and have the threads read from itI tend to prefer each thread to be managed by a single object, in which case I would try to move the bit of data to that manager and avoid the global. In most cases the design establishes dependencies and ownership of the resources, in which case you would not need the signals mechanism, as you can walk those dependencies.
The second part of the problem is how to, in a thread safe way, pass the data from the main thread to the rest of the threads, and in this particular case a single bit of data that has one value during most of the program and is set to a different fixed value at one point. Whether this is a global variable or part of the state of the thread manager does not really matter:
Combining both what you have is either a global or a local variable that will be modified either directly (global) or through function calls triggered from the main thread, either directly or through some signals mechanism. The modification of the flag must be done either with atomic operations (introducing memory fences) or by holding a mutex.
If the threads can be inactive (waiting on a condition variable), then you probably want to avoid the global, call the functions, lock on the mutex and inside the mutex both change the flag and use the condition variables to wake the waiting thread. The waiting thread would be responsible for checking the flag whenever it comes back from waiting in a condition.
Upvotes: 2
Reputation: 21616
Given you want to "signal all running threads that the application will exit" a manual reset even would do the trick.
You need to have each thread check the event occasionally and exit if the event has been signalled.
You then simply signal the event and wait for the threads to complete if you need to.
It's more complex if you need to do this more than once as a manual reset event must be reset manually and you'd need more code to make sure that every thread has received the notification before you reset the event for use in subsequent notifications, but given your question, this will work just fine.
Upvotes: 2
Reputation: 20730
boost::condition_variable
anticipate std::condition_variable
of C++11. As of today (2011) is implemented fully on POSIX interfaced systems (like UNIX / LINUX) but only mimicked on windows (with partial support)std::condition_varable
in windows with full support. But exists only from win6 (Vista and 2008). The world is still poulated by a lot of XP (that's why mingw -pthread is not supported in windows).That said, behind events (and condition variable) and mutex (and critical sections) there is a different scope of work:
Mutexes -essentially- protect code that must not be run concurrently. They essentially means "if this piece of code is already in execution wait until the other will complete it".
Events -essentially- protect the access to resource not yet been produced. It essentially means "wait here until someone can grant that it is possible to go over".
The difference is that mutexes are signaled by the same who has unsignaled them, while events are unsignaled by the one that had been waked-up from who signaled them. Note the the term "signal", here, has noting to do with the notion of signal in "boost signal", that is much more related to the concept of "delegate chain". But it is all another story.
Upvotes: 1