【问题标题】:Signalled and non-signalled state of event事件的信号和非信号状态
【发布时间】:2013-07-10 21:40:52
【问题描述】:
这对所有人来说可能是一个非编程问题,我确实阅读了线程同步对象,例如 event 以及它是如何设置为信号或非信号状态的。但是我无法理解这些术语信号和非信号。每个都以不同的方式表达,我有点困惑。
-
This link 声明
信号状态表示资源可供进程或线程使用。无信号状态表示资源正在使用中。
-
我从一个大学网站获得了一份简报,其中指出
处于信号状态的对象不会导致等待该对象的线程阻塞,而不处于信号状态的对象将导致等待该对象的任何线程阻塞,直到该对象再次变为信号状态.
-
This third link 声明了这一点
一个事件处于有信号状态意味着它有能力释放等待这个事件发出信号的线程。一个事件处于非信号状态意味着它不会释放任何正在等待这个特定事件的线程。
用一个例子简单解释一下这个概念会很有帮助。
【问题讨论】:
标签:
c
multithreading
winapi
【解决方案1】:
好的,你的 3 个引号不是不兼容的。但是让我们来看看实现:
每个可等待对象都附加一个布尔值,命名为信号状态,用于等待该对象;如果对象被发出信号,那么等待函数将不等待它;如果对象是未发出信号的,则等待函数将等待它。
现在,这如何应用于特定类型的对象?这取决于对象的性质,特别是与等待它相关的语义。实际上,信号状态是根据等待条件定义的。例如(有关详细信息,请参阅文档):
- 互斥体不属于时会发出信号。
- 进程/线程在完成时会发出信号。
- 信号量在其计数大于 0 时发出信号。
- 当一个可等待的计时器到期时,它会发出信号。
如果互斥体在拥有时发出信号,您可能会更喜欢,但实际上它是在不拥有时发出的。这对于让等待函数做正确的事情是必要的。
那么事件呢?嗯,它们是有些简单的对象,你可以随意给它们发信号和去信号,所以信号状态没有额外的意义:
- signaled:线程不会等待它。
- 无信号:线程将等待它。
事件也有这 SignalPulse 和 AutoReset 有点奇怪的东西(而且 IME 几乎不可能正确使用)。
现在,让我们看看你的报价:
信号状态表示资源可供进程或线程使用。无信号状态表示资源正在使用中。
其实这是一种解释。通常有一个资源是你试图仲裁的,并且通常你会等待当且仅当该资源正在使用中,所以它在使用资源和等待资源之间进行等价。但这不是技术要求,只是一个常见的用例。
处于信号状态的对象不会导致等待该对象的线程阻塞,而不处于信号状态的对象将导致等待该对象的任何线程阻塞,直到该对象再次变为信号状态.
正确,切中要害!
一个事件处于有信号状态意味着它有能力释放等待这个事件发出信号的线程。一个事件处于非信号状态意味着它不会释放任何正在等待这个特定事件的线程。
我觉得这个措辞有点混乱......但它与前一个相比并没有增加任何内容。
【解决方案2】:
简单的想法:"signalled" = "green light"
已发出信号:
如果您正在开车并且看到绿灯,您不会停下来(这是查看事件的线程,发现它已发出信号并继续进行而不阻塞)。
无信号:
如果您看到红灯,您会停下来等待它变成绿色然后继续(安全地知道其他线程现在都没有发出信号,因此正在等待或将在它们的...红灯处等待!)
【解决方案3】:
嗯,事实上所有这些解释都是一致的。
对事件的最简化(因此不是 100% 准确)的解释是将事件视为操作系统提供的一种标志服务。有信号的事件可以看作是设置的标志,而未发出的事件可以看作是未设置的标志。
为了实现基于标志的生产者/消费者线程系统,您通常执行以下操作(注意为简单起见,我忽略了进一步的同步机制):
static volatile int flag = 0;
static volatile char data = 'A';
// Some code to initialize the threads
void producer()
{
while (1)
{
Sleep(1000);
data++;
flag = 1;
}
}
void consumer()
{
while (1)
{
/* Busy wait for the occurence of more data */
while (!flag)
{
// wait for next data
}
flag = 0;
// process data
}
}
不幸的是,这会导致在繁忙的等待循环中浪费处理器周期,或者由于引入Sleep 调用以降低 CPU 消耗而导致不必要的执行延迟。两者都是不受欢迎的。
为了避免此类任务同步问题,操作系统提供了不同的类似标志的机制(例如 Windows 中的事件)。对于事件,设置和重置标志由操作系统调用SetEvent/ResetEvent 完成。要检查标志,您可以使用WaitForSingleObject。此调用有权使任务进入睡眠状态,直到发出事件信号,这在 CPU 消耗方面是最佳的。
这会将上面的例子变成这样:
static volatile char data = 'A';
static HANDLE newDataEvent = INVALID_HANDLE_VALUE;
// Some code to initialize the threads and the newDataEvent handle
void producer()
{
while (1)
{
Sleep(1000);
data++;
SetEvent(newDataEvent);
}
}
void consumer()
{
while (1)
{
if (WaitForSingleObject(newDataEvent, INFINITE) == WAIT_OBJECT_0)
{
ResetEvent(newDataEvent);
// process data
}
}
}
【解决方案4】:
我不太同意其他答案。他们没有抓住重点:
其中“signal property is false”等于“not-signal property is true”。
而且这三个定义都是指线程,但并不清楚,因为信号定义不是来自多线程,而是来自低级编程。
信号来自中断:
“如果该信号变为高电平(=中断),则将执行指针移至该函数”。
这就是信号的含义,它来自中断而不是线程。所以,not-signaled 的意思是,信号直到现在才变高。
在线程中,这变成:
"一个线程需要一个事件发生才能继续。如果它之前发生过,它可以继续;否则它会阻塞自己并等待它。"