2

I've studied that in concurrent programming there's something called "event semaphore" that works like this:

Let's say "sem" is the event semaphore object.

Threads executing sem.Wait() are suspended until someone calls sem.signalAll() that awake any thread waiting on sem.

I can't find anything like this in C#. The Semaphore class http://msdn.microsoft.com/it-it/library/system.threading.semaphore.aspx is what i call a counting semaphore, and is not exacly what i need. The ManualResetEventSlim http://msdn.microsoft.com/it-it/library/system.threading.manualreseteventslim.aspx is closer and i thought i could achive my goal by calling set(); folowerd by reset(); but i've read that it's not mean to be use like that and it might not awake all waiting thread.

PS, i don't know ho many waiting thread i have, i guess i could count them but i would prefere something like signalAll().

Pierre-Luc Pineault
  • 8,993
  • 6
  • 40
  • 55
flagg19
  • 1,782
  • 2
  • 22
  • 27

2 Answers2

2

There's nothing built-in, but you can write one fairly simply using Monitor. It's easiest if you encapsulate the logic (which isn't entirely obvious):

public sealed class Signaller
{
    public void PulseAll()
    {
        lock (_lock)
        {
            Monitor.PulseAll(_lock);
        }
    }

    public void Wait()
    {
        Wait(Timeout.Infinite);
    }

    public bool Wait(int timeoutMilliseconds)
    {
        lock (_lock)
        {
            return Monitor.Wait(_lock, timeoutMilliseconds);
        }
    }

    private readonly object _lock = new object();
}

Sample code using it:

public static class Program
{
    private static void Main(string[] args)
    {
        _startCounter = new CountdownEvent(NUM_THREADS);

        for (int i = 0; i < NUM_THREADS; ++i)
        {
            int id = i;
            Task.Factory.StartNew(() => test(id));
        }

        Console.WriteLine("Waiting for " + NUM_THREADS + " threads to start");
        _startCounter.Wait(); // Wait for all threads to have started.
        Thread.Sleep(100);
        Console.WriteLine("Threads all started. Setting signal now.");
        _signal.PulseAll();
        Thread.Sleep(1000);
        Console.WriteLine("\n{0}/{1} threads received the signal.\n\n", _signalledCount, NUM_THREADS);
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }

    private static void test(int id)
    {
        _startCounter.Signal(); // Used so main thread knows when all threads have started.
        _signal.Wait();
        Interlocked.Increment(ref _signalledCount);
        Console.WriteLine("Task " + id + " received the signal.");
    }

    private const int NUM_THREADS = 20;

    private static readonly Signaller _signal = new Signaller();
    private static CountdownEvent _startCounter;
    private static int _signalledCount;
}

Also see this thread: Is there a .Net class to do what ManualResetEvent.PulseAll() would do (if it existed)?

Community
  • 1
  • 1
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • Thanks it's exacly what i need. I tried using 'Monitor.Wait()' and 'Monitor.PulseAll()' but keep getting "Object synchronization method was called from an unsynchronized block of code." Now i undestand why. – flagg19 Aug 23 '13 at 14:54
2

Calling Set on a ManualResetEvent or ManualResetEventSlim will wake all waiting threads, provided you don't call Reset on it too soon after calling Set.

Other possibilities, depending on what you're trying to do, are Barrier and CountdownEvent, as well as Monitor, which Matthew Wilson explains quite well in his answer.

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351