据我所知,在开发多线程应用程序时,您必须使用监视器或锁等同步访问共享内存。
如何判断使用锁定代码块(proc1)的进程是否已完成使用代码的等待进程(proc2)?
答案 0 :(得分:5)
您是在谈论真正的操作系统流程,还是只讨论流程中的任务?
如果它只是一个流程中的任务,那么通常只是让锁为您完成工作。第二个任务尝试获取第一个任务当前拥有的锁,并且只是阻塞。当第一个任务释放锁定时,第二个任务将自动解除阻止。
如果您希望第二个主题可以选择先执行其他工作,则可以使用Monitor.TryEnter
代替 - 虽然这稍微更加繁琐。
如果你想等待但是你有更复杂的要求而不仅仅是锁定,那么可能需要Monitor.Pulse/PulseAll/Wait
。有关示例,请参阅this page的后半部分。
如果您实际上在谈论进程,那么您将需要使用系统范围的结构,例如Mutex
。它们比进程内.NET监视器“更重”,但允许进程间协调。
答案 1 :(得分:1)
其他进程通常被阻止,等待抢锁。当您的第一个进程释放它时,第二个进程可以抓取它。
换句话说,在一个典型的场景中,你并没有“告诉”其他线程,而是阻止它进入。
(在某些情况下,您确实希望告诉线程,通常由AutoResetEvent或ManualResetEvent处理)
答案 2 :(得分:1)
为此,您需要使用C#中提供的各种同步对象。可用同步对象的一些示例是System.Threading.Mutex,System.Threading.Semaphore,System.Threading.ManualResetEvent和System.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可以做到这一点。它阻塞调用线程,直到线程终止,同时继续执行标准消息泵送。