views:

622

answers:

5

I understand that when developing multithreaded applications you must synchronize access to shared memory using either, for instance, a monitor or a lock.

QUESTION

How do you tell the waiting process(proc2) that the process using the locked code block (proc1) has finished using the code?

+4  A: 

Are you talking about real operating system processes, or just tasks within a process?

If it's just tasks within a process, you typically just let locks do the work for you. The second task tries acquire the lock that the first task currently owns, and just blocks. When the first task releases the lock, the second task is automatically unblocked.

If you want to the second thread to have the option of doing other work first, you could use Monitor.TryEnter instead - although that's slightly more fiddly.

If you want to wait but you have more sophisticated requirements than just locking, then Monitor.Pulse/PulseAll/Wait are probably called for. See the second half of this page for an example.

If you're actually talking about processes then you'll need to use a system-wide structure such as a Mutex. These are "heavier" than in-process .NET monitors, but allow for inter-process coordination.

Jon Skeet
+1  A: 

The other process is usually blocked, waiting to grab the lock. When your first process releases it, the second process can grab it.

In other words, in a typical scenario, you don't 'tell' the other thread to go, instead you stop preventing it from going.

(There are scenarios where you do want to tell a thread to go, usually handled by a AutoResetEvent or a ManualResetEvent)

Matt Brunell
A: 

Reset events are particularly handy for this.

http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent.aspx

Bob
+1  A: 

To do this, you'll need to make use of the various synchronization objects available in C#. Some examples of the available synchronization objects are System.Threading.Mutex, System.Threading.Semaphore, System.Threading.ManualResetEvent, and System.Threading.AutoResetEvent (this is not an exhaustive list, but it's the basics). The exact synchronization object you'll want depends on your specific needs.

Mutex is probably the simplest to use, so I'll give it as an example. Say I have two functions that are running in two different threads (I'll stick with your own examples, proc1 and proc2). Both functions need to access the same variable, foo. In each function that accesses foo, you'll need to "lock" your mutex first. Then do whatever you need to do, then unlock it.

For example:

class bar
{
  private int foo;
  private System.Threading.Mutex lock = new System.Threading.Mutex;

  public void proc1()
  {
    lock.WaitOne();

    // do stuff to foo

    lock.ReleaseMutex();
  }

  public void proc2()
  {
    lock.WaitOne();

    // do stuff to foo

    lock.ReleaseMutex();
  }
};

Using this method, proc1 will execute. It will try to "grab" the mutex (lock). If the mutex is already grabbed, proc1 will go to sleep until the mutex is "released" by the other thread - proc1 will sit and wait, doing nothing (and eating no CPU cycles!) until the mutex is released. Then it will lock it and do its thing. No other thread will be able to grab the mutex until proc1 is done with it.

Another option is to use an Event. C# provides two types of events - manual reset and autoreset. I'll use a manual reset event for my example.

class bar
{
  private System.Threading.ManualResetEvent event = new System.Threading.ManualResetEvent;

  public void proc1()
  {
    // do stuff

    event.Set();
  }

  public void proc2()
  {
    event.WaitOne();
    event.Reset();

    // do stuff
  }
};

In this example, when proc2 is running it goes to sleep when it hits "event.WaitOne" and uses no CPU cycles until proc1 "sets" the event. Setting the event causes proc2 to wake up, and now it can do its thing. Because this is a manual reset event, the event will stay in the "set" state until event.Reset() is called.

Russell Newquist
I'd say the "basic" synchronization object in .NET is the monitor, actually... no need to get into Win32 objects unless you really have to :)
Jon Skeet
A: 

Depending on the nature of the multithreading, Thread.Join may do the trick. It blocks the calling thread until the thread terminates, while continuing to perform standard message pumping.

jchadhowell