我对条件变量的工作方式(在共享数据并发访问方面)的理解有些困惑
以下是伪C代码,以说明我当前的问题
// Thread 1: Producer
void cakeMaker()
{
lock(some_lock);
while(number_of_cakes == MAX_CAKES)
wait(rack_has_space);
number_of_cakes++;
signal(rack_has_cakes);
unlock(some_lock);
}
// Thread 2: Consumer
void cakeEater()
{
lock(some_lock);
while(number_of_cakes == 0)
wait(rack_has_cakes);
number_of_cakes--;
signal(rack_has_space);
unlock(some_lock);
}
Run Code Online (Sandbox Code Playgroud)
可以说我们目前有number_of_cakes = 0
,所以Thread 2
目前仍停留在此wait(rack_has_cakes)
。Thread 1
运行并number_of_cakes
以1 递增。然后它开始signal(rack_has_cakes)
-唤醒Thread 2
,不幸的Thread 2
是在Thread 1
调用之前唤醒unlock(some_lock)
,因此它再次回到睡眠状态,并且信号已丢失。
我对wait
和的内部运作感到非常困惑signal
。他们到底发生了什么?它们是否像某个布尔标志,当我们调用signal时将其自动设置为1并在等待成功时再次将其设置为0?到底是怎么回事?
线程2在线程1调用unlock(some_lock)之前被唤醒,因此它再次回到睡眠状态,并且信号已丢失。
不,那不是它的工作原理。我将使用C ++ std::condition_variable
进行引用,但是POSIX线程以及大多数互斥锁和条件变量的常规实现都以相同的方式工作。基本概念是相同的。
当线程2开始等待条件变量时,它已锁定互斥锁。等待()操作解锁互斥量和条件变量等待原子:
以原子方式释放锁,阻塞当前正在执行的线程,并将其添加到等待* this的线程列表中。
该操作被认为是“原子的”。换句话说,不可分割。
然后,当发出条件变量的信号时,线程将重新锁定互斥锁:
解除阻止后,无论出于何种原因,都将重新获得锁定并等待退出。
该线程不会在另一个线程“调用解锁”之前“返回睡眠”。如果互斥锁尚未解锁:当线程在被条件变量发出信号后唤醒时,线程将始终等待直到再次成功锁定互斥锁为止。这是无条件的。当wait()
返回互斥仍处于锁定状态。然后,只有这样,wait()
函数才会返回。因此,事件的顺序为:
一个线程已锁定互斥锁,将某些计数器,变量或任何类型的互斥锁保护的数据设置为另一线程正在等待的状态。这样做之后,线程会向状态变量发出信号,然后在互斥量处于闲置状态时将其解锁。
另一个线程wait()
在状态变量上锁定互斥之前。其中之一wait()
的先决条件是互斥之前必须锁定wait()
荷兰国际集团在链接状态变量。因此,wait()操作可以“原子地”解锁互斥锁。也就是说,没有实例将互斥锁解锁,并且线程尚未在条件变量上等待。当wait()
解锁互斥量,可以保证该线程将等待,它会醒来。您可以将其带到银行。
一旦条件变量发出信号时,wait()
荷兰国际集团线程不从返回wait()
,直到它重新锁定互斥。从条件变量接收到信号只是第一步,互斥锁必须在wait()
操作的最后一步中通过线程再次锁定。当然,这仅在信号线程解锁互斥锁之后才发生。
当一个线程获得由条件变量发出信号,它会返回从wait()
。但不是立即,它必须等到线程再次锁定互斥锁之后,无论它花费多长时间。它不会“回到睡眠状态”,而是要等待互斥锁再次锁定,然后再返回。您可以确保收到的条件变量信号将导致线程从返回wait()
,并且互斥锁将被线程重新锁定。并且由于原始的先解锁后等待操作是原子操作,所以可以确保您接收到条件变量信号。
归档时间: |
|
查看次数: |
1543 次 |
最近记录: |