22

I have a problem concerning the System.Threading Microsoft .NET namespace. In this namespace, many classes are defined in order to help me managing with threads. Well, I have a problem, but I do not know what to use, MSDN is vague and I still haven't got a clue of what classes do what. in particular, my problem concerns synchronization.

The problem

I have a certain number of threads (consider N threads). At a certain point a thread must stop and wait for at least one of the other thread to do something. Once one of the N - 1 threads has done a certain task, this thread notifies and the stopped thread will be able to proceed.

So it is just a synchronization issue: a thread must wait to be signalled, that's all.

Many classes

In System.Threading there are many classes provided in order to handle synchronization issues. There are WaitHandle(s), there are AutoResetEvent(s), there are ManualResetEvent(s) and so on...

Which one whould I use?

The question

My question is: can anybody summarize me which class I should use in order to solve my problem? Could you please tell the most important differences between these classes, or other classes?

The point is that I havn't really understood what class is responsible of in the synchronization matter: what is the difference, for example, between a WaitHandle and an AutoResetEvent or ManualResetEvent?

What about lock?

In order to handle many threading issue, .net provides lock functionalities and the Monitor class. Is this couple good for my needs?

Thankyou

Paul R
  • 208,748
  • 37
  • 389
  • 560
Andry
  • 16,172
  • 27
  • 138
  • 246
  • Look at this thread: http://stackoverflow.com/questions/209281/c-equivalent-to-javas-wait-and-notify – Ozair Kafray Jun 16 '11 at 11:54
  • You might find the [Task Parallel Library](http://msdn.microsoft.com/en-us/library/dd460717.aspx) useful, depending. – Grant Thomas Jun 16 '11 at 12:03
  • @Ozair That post is about a specific notification, not always the best. See Marcs answer and note the remarks about 'missing a message'. – H H Jun 16 '11 at 12:05
  • 1
    BTW `AutoResetEvent` and `ManualResetEvent`s are all `WaitHandle`s, they just wrap the ctor of `WaitHandle` and pass different parameters to it so it will be an auto reset or manual reset. Either way you're using a wait handle and that greatly simplifies the amount of information you need to look up – Allen Rice Jun 16 '11 at 12:19
  • 2
    Also when you say that the thread must be signaled, keep in mind that we are assuming that you dont need to pass any information at that point, just signal it to continue. Reword the question if that assumption isn't correct :) – Allen Rice Jun 16 '11 at 12:21
  • @Allen: Well, essentially I also need to pass data to the stopped thread, however I didn't want to overloan the question with too many things :) – Andry Jun 16 '11 at 12:38
  • @Andry, We can give you a much better answer if we know everything :) What do you need to pass? Are these threads within the same proccess? Is this something the signaling thread has or is this just a value stored somewhere? Is it acceptable for the signaling thread (or something else) to store it somewhere and then have the signaled thread go look it up or does this have to be passed from one thread to another? – Allen Rice Jun 16 '11 at 12:42

5 Answers5

19

Albahari's book is amazing, you should really read through it some time. Its grown alot lately!

What you want

You want an EventWaitHandle (EWH), they are nice because there is nothing to pass around, they are used for signaling threads (either in the same or in a different process) and as the name implies, they can be waited on.

How you use it

You would open one on the thread that is doing the waiting, you open it with a given name that the other thread is going to know about. Then you wait on that wait handle.

The signaling thread will open an existing wait handle of the same name (name is a string) and call set on it.

Differences

AutoResetEvents and ManualResetEvents both inherit from EWH and they are really just EWH's, they just act differently. Which one you want just depends on if you want the EWH to act as a gate or a turnstyle. You only care about this if you are using the wait handle more than once or you are waiting on that wait handle by more than one thread. I've used wait handles a decent amount (I suppose) and I don't think I've ever used a Manual.

Important to know

  • Whatever you do, dont pass an instance of a wait handle around, they are meant to be opened seperately by their own threads. The name you specify will ensure that they are the "same" wait handle.

  • If the threads are in different processes, then you will HAVE to prefix the name of the EWH with @"Global\", otherwise the names of the wait handles will be encapsulated within the same process. Alternatively, if you are using them all within the same process, dont use the global namespace. When you don't specify a prefix with a backslash, one is automatically added to keep it private, but you don't need to know that prefix.

  • Keep in mind that EWH's can be permissioned, and if you run into issues with that I reccomend that you use EventWaitHandleRights.FullControl, but you can browse the full EventWaitHandleRights enumeration here.

  • I like to name my EWH's with a Guid.NewGuid().ToString("N") (Guid.NewGuid & Guid.ToString). I typically do this when the signaling thread is created, since you can easily pass information to it at that time. So in that case, the initial thread creates the string and passes it to the signaling thread when its created. That way both threads know of the name, without having to do any fancy cross-thread passing of variables.

  • EWH implements IDisposable so wrap it in a using block

Race conditions

EWH's are nice because if for whatever reason the signaling thread opens and signals the wait handle before the waiting thread even creates it, everything will still work and the waiting thread will be signaled the instant it hits the wait.

Because of this, though, the thread that is waiting on it will need to have some error trapping because you will need to call OpenExisting. If you call one of the ctor's and the EWH is already opened, you'll get a UnauthorizedAccessException or a WaitHandleCannotBeOpenedException thrown as described here, under Exceptions. You'll still be able to open that EWH and get the functionality you need, you may just have to open it instead of create it.

Allen Rice
  • 19,068
  • 14
  • 83
  • 115
  • 1
    YOU OPENED MY EYES!!! EventWaitHandle(s) are amazing!!! So just the name is necessary I do not need to pass references..... is it correct???????????? – Andry Jun 16 '11 at 12:54
  • 1
    That is correct, do nooooooooot pass them around heh, thats the whole point is that you open them by name and there is no passing. They really are awesome because of how amazingly easy to use they are and the concept is pretty simple. There are a few caveats but I've covered all the ones I've ever encountered :) – Allen Rice Jun 16 '11 at 12:57
  • OK one more question only, however you have already got the correct answer, EWH are application and system wide, however if I do not place the global namespace stuff I am sure that those etws won't be accessed by other applicationns right?????? What about Mutex??? this is just for my personal info: MSDN says that Mutex is specific for application wide reasons, so they already come with gloab namespace?????? to make it simple: if I instantiate a mutex, will it be available also bu others???? THANKYOU VERY MUCH – Andry Jun 16 '11 at 13:12
  • 1
    Right, without the global namespace, you cannot access this EWH at all from another process. I'm not sure about `Mutex`, I've never used it because I've never encountered a simple signaling situation that I felt needed any functionality or speed over what the EWH offers. On MSDN, their example of a mutex says that its a local Mutex and in that example they dont prefix it with `@"Global\"` so I **assume** the rules are the same as for an EWH. As for the accessibility of a `Mutex`, I have no idea, sorry. – Allen Rice Jun 16 '11 at 13:30
  • 3
    @allenrice, only unnamed mutexes are local to the process. Any named mutex is system wide. Add `@"Global\\"` to it makes it global between terminal server sessions (I.e. d everyone can see it), adding `Local\\` or nothing makes it visible to the current session only. So it _is_ a bit different in that respect. – Abel Dec 16 '15 at 02:14
9

The difference between an auto-reset event and a manual-reset event is that an auto-reset event clears itself (closes) after one use, so only one item gets through the gate. I suspect an AutoResetEvent would do nicely here. Personally I tend to use Monitor more, though - it has lower overheads, but you do need to be a bit careful; your first thread must be sure to own the lock before any of the others, i.e

object lockObj = new object();
lock(lockObj) {
    // start the workers, making lockObj available to them

    Monitor.Wait(lockObj);
}

with the workers doing something like:

// lots of work
// now signal
lock(lockObj) Monitor.Pulse(lockObj);
// other work

Holding the lock originally means that we don't miss any messages while we are spinning up workers, as any workers getting to lock(lockObj) will be blocked until the original thread releases the lock at Monitor.Wait. The first thread the Pulse will signal our original thread to continue.

Ozair Kafray
  • 13,351
  • 8
  • 59
  • 84
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • +1 for noting that work thread/s may reach the barrier before the constructing thread reaches the wait(). – Martin James Jun 16 '11 at 12:37
  • The term for "clearing itself" is "non-signalled" or "unsignalled" (as with all waitable objects in Windows they are either signalled or unsignalled). – Richard Jun 16 '11 at 12:38
  • @Andry sure! Wait and Pulse/PulseAll. When calling wait, you surrender the lock and join the waiting queue; a call to Pulse moves one thread from the waiting queue to the ready queue (PulseAll moves all); when the pulse-thread releases the lock, the originally waiting thread can obtain it, et voila – Marc Gravell Jun 16 '11 at 12:49
5

There is a great free e-book on this topic (and check part 2)

For what to use and when, there are many topics about this on SO, like this one: What is the difference between ManualResetEvent and AutoResetEvent in .NET?, to quote Dan Goldstein:

"Yes. It's like the difference between a tollbooth and a door. The ManualResetEvent is the door, which needs to be closed (reset). The AutoResetEvent is a tollbooth, allowing one car to go by and automatically closing before the next one can get through."

Community
  • 1
  • 1
Denis Biondic
  • 7,943
  • 5
  • 48
  • 79
  • Yeah, after I read the free version I imminently went on Amazon and bought a copy :) Although, to be honest, the best part of the book is this one about threading... – Denis Biondic Jun 16 '11 at 12:51
1

You can use the AutoResetEvent or the ManualResetEvent. The only difference is whether you have to call Set() yourself or have it done.

H H
  • 263,252
  • 30
  • 330
  • 514
0

Can it happen, or does it matter, if 'one of the N - 1 threads has done a certain task' happens before the 'a thread must stop and wait' reaches its 'certain point' ? This may affect your choice of synchro.

Rgds, Martin

Martin James
  • 24,453
  • 3
  • 36
  • 60
  • well, worker threads (N - 1 ones) always work, they do not block. Its just that the 1 thread (the one that stops) who needs to stop, it is a necessity, it cannot choose whether stopping or not, it must stop, then, by timeout or by signal, it can proceed further. Thanlyou for asking :) – Andry Jun 16 '11 at 12:35