views:

259

answers:

2

Hi

In previous question of mine, someone had meantioned that using Semaphores were expensive in C# compared to using a monitor. So I ask this, how can I replace the semaphore in this code with a monitor?

I need function1 to return its value after function2 (in a separate thread) has been completed. I had replaced the Semaphore.WaitOne with a Monitor.Wait and the Semaphore.Release with a Monitor.PulseAll but the PulseAll was being triggered before the Wait causing the program to hang. Any idea how to avoid that race condition?

Semaphore semaphore = new Semaphore(0,1);
byte b;
public byte Function1()
{
    // new thread starting in Function2;

    semaphore.WaitOne();
    return b;
}

public void Function2()
{
    // do some thing
    b = 0;
    semaphore.Release();
}
+5  A: 

You can do this with a WaitHandle instead of a Semaphore. This would be the simplest alternative, and perform better than a Semaphore:

ManualResetEvent manualResetEvent = new ManualResetEvent(false);
byte b;
public byte Function1()
{
    // new thread starting in Function2;

    manualResetEvent.WaitOne();
    return b;
}

public void Function2()
{
    // do some thing
    b = 0;
    manualResetEvent.Set();
}
Reed Copsey
To explain this answer further for other readers - `Semaphore` is only necessary when you need to allow some fixed number of threads > 1 to acquire a shared resource. It is similar to `Monitor` but neither are the correct semantics for the original question, which is trying to solve the problem of "wait until this operation is done." For those semantics, a wait handle (`ManualResetEvent/AutoResetEvent` is typically more appropriate than a critical section (`lock`/`Monitor`).
Aaronaught
@Aaronaught: Very nice explanation of the details as to why this is a better approach in this case.
Reed Copsey
@Aaronaught, @Reed: geez. I have just deleted a part of one of my other answers, on the basis that `Semaphore` (and `WaitHandle`, in general) is more heavy-weight than Monitor. I do feel that it is semantically more correct (in that particular case, Semaphore would be the best fit) - but should I e.g. unroll the edit and leave the semaphore example there, because it is semantically more correct? Just wondering... Any thoughts?
andras
@andras: Personally, I go for the option that matches the problem the best. In this case, a WaitHandle is the appropriate option. The overhead of all of the "extra" stuff required to use a Monitor, and have it perform correctly, outweighs the performance gains. Semaphore, in this case, isn't really correct, since there's only a single thread blocking.
Reed Copsey
@Reed: I could not agree more - however, the question has a few holes.1. the title is in serious contradiction with the sample code. If I take the title, the OP needs semaphores. If I take the sample code, he needs events. 2. we do not know if the OP really needs high perf or just suffers from POS (premature optimization syndrome). I suspect the latter. With that said, if the question is really what the title says, I just could not resist answering. Mea culpa. :P
andras
@andras: `Semaphore` is kind of a weird class, it has mutex syntax but critical-section semantics, so one generally shouldn't use it at all except when multiple-but-limited concurrency is really necessary (i.e. rarely). As for `ManualResetEvent`, it's a better choice design-wise than a `Monitor`-based spinlock if those are the semantics you want - and the `Slim` classes in .NET 4 should make any performance worries go away (not that I've ever noticed any slowdown prior to this). I might be missing something but I'm pretty sure that's the important bit.
Aaronaught
@Reed, @Aaronaught: thanks for pointing out the importance of this. I have updated the answer accordingly. (I believe. :)@Aaronaught: Monitor is a weird beast, I believe. I am not really sure what you mean about "`Monitor`-based spinlock". It is true that it might spin, it does it intelligently however. It also detects contention and it inflates to a flat lock if necessary etc. Being the primary synchronization primitive, a lot of thought went into it, I guess. `ManualResetEventSlim` in .NET 4 happens to use it extensively.... :P
andras
@Aaronaught: FYI, the "Semaphore Files" :) http://stackoverflow.com/questions/2528907/c-spawn-multiple-threads-for-work-then-wait-until-all-finished(Maybe I should change that to an event based counter as well....)(Oh, and "flat lock" = "fat lock" in the above.) :P
andras
@Aaronaught: Hmmmm. After a short break, I've came to the realization that semaphores (or locks with counters) are just so much more convenient in some cases, after all. :P (I.e. I think I would have a pretty hard time answering the above question with auto/manualresetevents.)
andras
@Andras: I actually prefer to use a ManualResetEvent (in conjunction with a counter) to answer the above question. I'll add an answer there to demonstrate.
Reed Copsey
@andras: I use the exact same approach as Reed, except using the `ThreadPool` instead of free threads. I actually saw the other question and left it alone because I always trot out the same code snippet and figured I'd give someone else a chance (like Reed). :P Having said that, you *could* use a `Semaphore` as a lazy-man's countdown latch, but I just don't like the way it looks, and `Interlocked` is essentially lock-free.
Aaronaught
@Aaronaught: Typically, I do this via the ThreadPool as well, although it depends somewhat on the work involved. :)
Reed Copsey
@Aaronaught, @Reed: I guess I've been guilty of being lazy all the way along. It never felt right, but I just used it anyway. (I did not need it that often and it didn't seem to matter perf-wise.) Now it seems so clear. d :-o <= yeah, I've looked this one up. It was meant to be a "hats off to you" smiley. :)
andras
+1  A: 

@Reed provided an elegant solution if you need to wait for multiple threads.

You might not want to use Monitor fro this. As @Reed pointed out, an event would suffice and would provide the cleanest and most understandable solution that matches the requirements of your code.
The overhead of using real operating system sync primitives will most probably not matter in your case and using e.g. Monitor would provide only diminishing returns at the cost of much higher complexity.

With that said, here is an implementation using Monitor and signaling.

You can use a bool flag - guarded by the lock - to indicate that you have finished and avoid waiting in that case. (A)
If you really start a new thread within Function2() where the comments indicate and use lock() around both WaitOne() and Release(), you do not need the flag at all. (B)

A, using a flag:

class Program
{
    static object syncRoot = new object();
    //lock implies a membar, no need for volatile here.
    static bool finished = false;
    static byte b;

    public static byte Function1()
    {
        lock (syncRoot)
        {
            //Wait only if F2 has not finished yet.
            if (!finished)
            {
                Monitor.Wait(syncRoot);
            }
        }
        return b;
    }

    static public void Function2()
    {
        // do some thing
        b = 1;
        lock (syncRoot)
        {
            finished = true;
            Monitor.Pulse(syncRoot);
        }
    }

    static void Main(string[] args)
    {
        new Thread(Function2).Start();
        Console.WriteLine(Function1());
    }
}

B, starting a thread from Function1:

class Program
{

    static object syncRoot = new object();
    static byte b;

    public static byte Function1()
    {
        lock (syncRoot)
        {
            // new thread starting in Function2;
            new Thread(Function2).Start();
            Monitor.Wait(syncRoot);
        }
        return b;
    }

    static public void Function2()
    {
        // do some thing
        b = 1;
        //We need to take the lock here as well
        lock (syncRoot)
        {
            Monitor.Pulse(syncRoot);
        }
    }

    static void Main(string[] args)
    {
        Console.WriteLine(Function1());
    }
}
andras