2

我知道在开发多线程应用程序时,您必须使用例如监视器或锁来同步对共享内存的访问。

问题

您如何告诉等待进程(proc2)使用锁定代码块(proc1)的进程已完成使用该代码?

4

5 回答 5

5

您是在谈论真正的操作系统进程,还是只是进程中的任务?

如果它只是流程中的任务,您通常只需让锁为您完成工作。第二个任务尝试获取第一个任务当前拥有的锁,然后阻塞。当第一个任务释放锁时,第二个任务自动解锁。

如果你想让第二个线程可以选择先做其他工作,你可以Monitor.TryEnter改用 - 虽然这有点复杂。

如果您想等待,但您有比锁定更复杂的要求,那么Monitor.Pulse/PulseAll/Wait可能需要。有关示例,请参见本页的后半部分。

如果您实际上是在谈论进程,那么您将需要使用系统范围的结构,例如Mutex. 这些比进程内 .NET 监视器“更重”,但允许进程间协调。

于 2009-11-05T22:48:12.157 回答
1

其他进程通常被阻塞,等待抢锁。当您的第一个进程释放它时,第二个进程可以抓取它。

换句话说,在典型情况下,您不会“告诉”另一个线程去,而是停止阻止它去。

(在某些情况下,您确实想告诉线程去,通常由 AutoResetEvent 或 ManualResetEvent 处理)

于 2009-11-05T22:48:20.023 回答
1

为此,您需要利用 C# 中可用的各种同步对象。可用同步对象的一些示例是System.Threading.MutexSystem.Threading.SemaphoreSystem.Threading.ManualResetEventSystem.Threading.AutoResetEvent(这不是一个详尽的列表,但它是基础知识)。您需要的确切同步对象取决于您的特定需求。

互斥锁可能是最简单的使用,所以我举个例子。假设我有两个函数在两个不同的线程中运行(我将坚持使用您自己的示例,proc1 和 proc2)。两个函数都需要访问同一个变量 foo。在每个访问 foo 的函数中,您需要先“锁定”您的互斥锁。然后做任何你需要做的事情,然后解锁它。

例如:

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();
  }
};

使用此方法,proc1 将执行。它将尝试“抓住”互斥体(锁)。如果互斥锁已经被抓取,proc1 将进入睡眠状态,直到互斥锁被另一个线程“释放” - proc1 将坐下来等待,什么都不做(并且不吃任何 CPU 周期!),直到互斥锁被释放。然后它会锁定它并做它的事情。在 proc1 完成之前,没有其他线程能够获取互斥锁。

另一种选择是使用事件。C# 提供两种类型的事件 - 手动重置和自动重置。我将在我的示例中使用手动重置事件。

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
  }
};

在此示例中,当 proc2 运行时,它会在遇到“event.WaitOne”时进入睡眠状态,并且在 proc1“设置”事件之前不使用 CPU 周期。设置事件会导致 proc2 被唤醒,现在它可以做它的事情了。因为这是一个手动重置事件,所以事件将保持在“设置”状态,直到调用 event.Reset()。

于 2009-11-05T23:03:09.807 回答
0

重置事件对此特别方便。

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

于 2009-11-05T22:48:31.940 回答
0

根据多线程的性质,Thread.Join 可以解决问题。它阻塞调用线程,直到线程终止,同时继续执行标准消息泵送。

于 2009-11-06T00:03:41.010 回答