Archived

This topic is now archived and is closed to further replies.

Events vs. Condition Variables

This topic is 5147 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I learned to program Win32 first, so I have an affinity for events (and semaphores) over mutexes and condition variables. However, just about everything I read about condition variables states that they are a superior mechanism over events, often safety is reason cited. What is not explained, or what I do understand anyway, is why. My experience thus far would lead me to believe Win32 events are less error prone than Linux condition variables due to stronger guarantees and post-condition that events offer over condition variables. Win32 events synchronize themselves, you do not have to employ an additional mutex as you do with condition variables, and events are never spuriously awoken as condition variables may be. It is possible to lose the signal with both events and condition variables. If you signal an already signaled event, it does not double-bang. Only one "awakening" occurs (there is a bug in the comport code example on MSDN due to this). With condition variables, if no one is waiting on it when it is signal, the signal is lost. (This was the first bug I wrote using cd''s, I expected the signal to persist until it was waited on). There are solutions for both of these issues, with events you cannot rely on state at the time of the event, you have to check the state at the time of the awakening. e.g. keep reading characters from the comport until there are no more, don''t just read how many were available when the event was signaled. With condition variables, you have to check the condition (the variable that the ‘condition variable’ signals for) prior to waiting (to see if it''s ready now). Events have a couple of configuration options that tailor their behavior for several different uses. When the event auto-resets, it is atomically reset upon a wait and you are guaranteed that one and only one thread will be awoken. Condition variables do not make a ''there can only be one'' guarantee, and all waiting threads may contend for the mutex upon signaling. (This causes thread-thrashing and is problematic on latency sensitive systems and high-capacity servers using thread-pools. I suppose this is a QoI issue, condition variables could be implemented without awakening all the waiting threads for one-shot-signals, but posix does not require this.) If you desire the ‘signal and forget’ behavior of condition variables, there is a PulseEvent Win32 API call that behaves this way (if no threads are waiting on the event, the signal is lost). One functional difference, is that you can call pthread_cond_signal or pthread_cond_broadcast on any condition variable, whereas you must decide at creation whether an event is automatic (auto-reset, behaves like cond signal) or manual (behaves like cond broadcast). The Win32 method is to wait on more than one event if you need this behavior; an automatic event for single-shots, and a manual event for broadcast. That is why I think events are easier to use, and are a superior solution. Why do so many think that condition variables are better?

Share this post


Link to post
Share on other sites
For one thing: Win32 events aren''t very portable, and do very much influence the structure of the code. This in itself, is reason enough to consider them superior for many people. Events might be better on Windows, in most cases, I''m not sure.

Share this post


Link to post
Share on other sites
Personally, I don''t see anything wrong with event style synchronization primitives. Most of the time people saying this kind of thing are refering to a paper by P. Brinch-Hansen in 1974(?). I think it was published by the ACM, but I don''t remember the title. Something about concurrent programming I think.

Essentially there are two objections that I remember. Number one is that using events for synchronization somehow depend on knowing the relative speed of the two synchronizing threads/processes. Don''t ask me to explain this one, I was an undergrad when I read it. Number two is that events are error prone because there is no explicit relationship between the event object and the data that it guards, so in large scale designs it is possible to forget to synchronize properly.

Sorry, not very much help, but it should be enough to do a search and find the original paper.

Share this post


Link to post
Share on other sites
quote:
CWizard
For one thing: Win32 events aren''t very portable, and do very much influence the structure of the code. This in itself, is reason enough to consider them superior for many people. Events might be better on Windows, in most cases, I''m not sure.


Aside from waiting on multiple events simutaneously (I have an idea on how to emulate this as well, but no implementation to back it up yet), I have written a wrapper around a condition variable that behaves very much like a Win32 event. I believe you could use two Win32 events (and a mutex) and emulate a condition variable as well.

...
quote:
SiCrane
Essentially there are two objections that I remember. Number one is that using events for synchronization somehow depend on knowing the relative speed of the two synchronizing threads/processes. Don''t ask me to explain this one, I was an undergrad when I read it. Number two is that events are error prone because there is no explicit relationship between the event object and the data that it guards, so in large scale designs it is possible to forget to synchronize properly.

Sorry, not very much help, but it should be enough to do a search and find the original paper.



Why would you try to guard data with an event? I think that''s a strawman. "Egads! Booleans are no good for floating-point calculations!"

I did read something about having to know the relative speed of the processes, but no example was given. I was not able to think of an example where condition variables did not also bind the execution times together. I''ll try to track down more information about the relative speed issue.

Share this post


Link to post
Share on other sites
quote:
Original post by Magmai Kai Holmlor
Why would you try to guard data with an event? I think that''s a strawman. "Egads! Booleans are no good for floating-point calculations!"



Because in 1974 there were very few synchronization primitives available. I want to say that the only other proven method was spin-locks, as this was in the days when only load and stores could be considered atomic operations on the processor. Try to keep things in perspective: this is the paper that introduced monitors. Hoare wouldn''t write about mutexes until a year later.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
On past projects i''ve used mutex and other synchronization objects. I only used them for data protection between threaded acccess, but i suppose multithreaded signaling is a possiblity as well, the only issue i would think would be the blocking on the waiting thread for the signals and signal registeration still would run into race conditions.

Recently I''ve read Pratical Statecharts in C/C++ by Miro Samek. It really opened my eyes to event based programming techniques and the role of hiearchical state machines. I''ve had a chance to implement an engine based upon these techniques and I can see their power and simplicity. Events by their nature are mobile, easilty crossing boundaries between modules, threads, processes, computers, etc. That loose copuling, in conjunction with the active object programming techinques as outlined in the book, can greatly reduce the complexity of programs. One thing i''ve noticed is the inherit latency of event based systems. Even though they usually are simpler and more efficient than a traditional polled or slot/signal approach, they suffer from higher latencies. For most applicaitons, I dont think this is a major issue, and in all cases an event based implementation can be reduced down into a more direct slot/signal implementaiton, with the tradeoff in compleixty and size.

Defintely using mutex for multithreaded data protection is a good idea, as that is their function. However using these object to handle flow of control distributedly and asychonrously, proably is not the best technique. I''ve found events to fill that role more efficiently, from my limited expereince.

However for systems which require high performance and are
willing to sacrifice the loose coupling and simplicity which events provide, using those condition variables proably would be a better choice. But there is a point in which the additional complexity may outweight the performance gains.

-ddn

Share this post


Link to post
Share on other sites
I prefer the three building blocks of:

- atomic compare/exchange
- counting semaphores
- monitors

You can easily build the others on top of this, if you need them.

I also prefer an OS that has native support for waiting for multiple of these at the same time, select() or poll() style. Thus, there''s something to be said for all of these (except compare/exchange) to be file descriptors. Or, under Windows, HANDLEs and WaitForMultipleObjects().

Btw: that''s one thing Windows NT got right: WaitForMultipleObjects(), and making all the synchronizable primitives except CRITICAL_SECTION be waitable with that same function, including the message queue!

Share this post


Link to post
Share on other sites
quote:
Original post by SiCrane
quote:
Original post by Magmai Kai Holmlor
Why would you try to guard data with an event? I think that''s a strawman. "Egads! Booleans are no good for floating-point calculations!"



Because in 1974 there were very few synchronization primitives available. I want to say that the only other proven method was spin-locks, as this was in the days when only load and stores could be considered atomic operations on the processor. Try to keep things in perspective: this is the paper that introduced monitors. Hoare wouldn''t write about mutexes until a year later.


Oh, are these criticisms stale then? It''s very possible Win32 events do not work anything like the events around back then.

Share this post


Link to post
Share on other sites
Finally found the paper (took me forever because I was off by year):

Per Brinch Hansen, Concurrent Programming Concepts, ACM Computing Surveys, Vol. 5, No. 4, December, 1973.
http://www.acm.org/pubs/articles/journals/surveys/1973-5-4/p223-hansen/

I believe you need to have an account with the ACM in order to get at the full text though.

Share this post


Link to post
Share on other sites
quote:
Original post by Magmai Kai Holmlor

Oh, are these criticisms stale then? It''s very possible Win32 events do not work anything like the events around back then.




Stale or not, people still refer to the darn paper.

Share this post


Link to post
Share on other sites
Hi,

I recently program with multi-threads (for about 1 year) under Linux only. I tried to follow your discussion. I will just tell my point of view, just to enlarge my understanding.

quote:
Original post by Anonymous Poster
One thing i''ve noticed is the inherit latency of event based systems. Even though they usually are simpler and more efficient than a traditional polled or slot/signal approach, they suffer from higher latencies. For most applicaitons, I dont think this is a major issue, and in all cases an event based implementation can be reduced down into a more direct slot/signal implementaiton, with the tradeoff in compleixty and size.



Isn''t that latency that failed with the cpu battle between AMD and Intel ?
Latency is a real problem because your cpu do nothing, and may surely have better things to do.

quote:

Defintely using mutex for multithreaded data protection is a good idea, as that is their function. However using these object to handle flow of control distributedly and asychonrously, proably is not the best technique. I''ve found events to fill that role more efficiently, from my limited expereince.

-ddn


Yes, but I think again, seemly as above, that mutexes and condition waitings could do the same work with lower latency.
Flows depends on the data; and this may be an important thing for me: if you do events for handle flows, you must protect your data with something like mutex, otherwise, you may suffer from synchronization problem. Your flow may not be read at the same speed and frequency than its writting.

I surely may be wrong, this will permit me to understand why.

thank you.

Share this post


Link to post
Share on other sites
quote:
SiCrane
Finally found the paper (took me forever because I was off by year):

Per Brinch Hansen, Concurrent Programming Concepts, ACM Computing Surveys, Vol. 5, No. 4, December, 1973.


I believe you need to have an account with the ACM in order to get at the full text though.



Probably about time I opened an account.

...
OT
The AP was talking about two different sorts of events - signaling events such as posix condition variables and Win32 Event objects which will either use far less CPU time or have less latency than polling systems.

Event driven programming is something different though related; you have a queue in which you post messages and sometime later the state machine processes the posted events. To operate efficiently, an Event object is used internal to the message queue, so the state machine is awoken to do work only when there is a message to do work on. This (obviously) has more latency than direct invocation, but also makes you to design the system to work in ''virtual time'' instead of ''real time'' which has advantages. (Unless you need real-time, and video games are _not_ real-time applications. They are "online" meaning the processing is done as data is made available but it is not a critical fault if the data in not processed by a deadline. All we need is a nominal level of performance, not a guaranteed level; ergo variable frame-rates).

Share this post


Link to post
Share on other sites