3

What I want to do

I want to create some threads, say thread A, B, C, and block them until an event occurs. When an event occurs, I want to release only one thread.

For Example:

Before event occurs:
Thread A : blocked
Thread B : blocked
Thread C : blocked

After event occurs:
Thread A : blocked
Thread B : unblocked
THread C : blocked

I read that AutoResetEvent can do this but I can't specify which thread to be unlocked, and ManualResetEvent will unblock all the blocked threads.

Is there a way to achieve what I want to do?

Community
  • 1
  • 1
kabichan
  • 1,063
  • 4
  • 19
  • 49
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Dec 09 '13 at 00:16
  • How do you determine which thread should become unblocked? – Lukazoid Dec 09 '13 at 00:21
  • A thread that was popped from Ready queue will be the one that's going to be unblocked. – kabichan Dec 09 '13 at 00:25

2 Answers2

5

Create multiple instances of ManualResetEvent, one for each Thread and use ManualResetEvent.WaitOne() in each Thread, e.g.

public void StartThreadA()
{
    _mreA = new ManualResetEvent();
    _threadA = new Thread(new ThreadStart(() => 
    {
        _mreA.WaitOne();
        // Continue
    });
}

When your even happens you can then handle it like so:

private void OnSomeEvent()
{
   _mreA.Set();
}

This is very limited in terms of scale, if you intend to use a large number of threads, I would suggest using a dictionary to look-up the ManualResetEvent for each thread.

Update

As I am now aware you are using a queue of threads I would do something like the following:

private Queue<ManualResetEvent> _queuedThreads = new Queue<ManualResetEvent>();

public void EnqueueThread()
{
    var mre = new ManualResetEvent();
    var thread = new Thread(new ThreadStart(() =>
    {
        mre.WaitOne();
        // Continue
    });

   _queuedThreads.Enqueue(mre);
}

private void OnEvent()
{
    var mre = _queuedThreads.Dequeue();
    mre.Set();   
}
Lukazoid
  • 19,016
  • 3
  • 62
  • 85
0

You should consider using a Semaphore rather than a ManualResetEvent or AutoResetEvent.

There is a good basic example in the documentation here.

Also, here is a related stack overflow question.

Community
  • 1
  • 1
Joe Enzminger
  • 11,110
  • 3
  • 50
  • 75
  • Thank you for your suggestion. But in this particular problem, I had to suspend/resume threads without using the deprecated methods, locks, or semphores. – kabichan Dec 09 '13 at 01:17
  • Unless you use a `Semaphore` or `SemaphoreSlim` per `Thread`, you will still lack control about which `Thread` to resume. – Lukazoid Dec 09 '13 at 08:48