C#多线程 - 告诉使用锁定代码完成第一个进程的等待进程?

时间:2009-11-05 22:45:12

标签: c# multithreading locking monitor

据我所知,在开发多线程应用程序时,您必须使用监视器或锁等同步访问共享内存。

问题

如何判断使用锁定代码块(proc1)的进程是否已完成使用代码的等待进程(proc2)?

5 个答案:

答案 0 :(得分:5)

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

如果它只是一个流程中的任务,那么通常只是让锁为您完成工作。第二个任务尝试获取第一个任务当前拥有的锁,并且只是阻塞。当第一个任务释放锁定时,第二个任务将自动解除阻止。

如果您希望第二个主题可以选择先执行其他工作,则可以使用Monitor.TryEnter代替 - 虽然这稍微更加繁琐。

如果你想等待但是你有更复杂的要求而不仅仅是锁定,那么可能需要Monitor.Pulse/PulseAll/Wait。有关示例,请参阅this page的后半部分。

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

答案 1 :(得分:1)

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

换句话说,在一个典型的场景中,你并没有“告诉”其他线程,而是阻止它进入。

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

答案 2 :(得分:1)

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

Mutex可能是最简单的使用方式,因此我将以此为例。假设我有两个在两个不同线程中运行的函数(我将坚持使用您自己的示例,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()。

答案 3 :(得分:0)

答案 4 :(得分:0)

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