信号和非信号状态的事件

时间:2013-07-12 10:55:49

标签: c multithreading winapi

对于所有人来说,这可能是一个非编程问题,我读过有关线程同步对象,例如事件以及如何将其设置为信号或非信号状态。但是我无法理解这些术语信号和非信号。每个人都用不同的方式表达,我有点困惑。

  1. This link表示

      

    信号状态表示资源可供进程或线程使用。未发信号状态表示资源正在使用中。

  2. 我从大学网站获得了一个强力点演示文稿,其中说明了

      

    处于信号状态的对象不会导致等待对象阻塞的线程和未处于信号状态的对象将导致等待该对象的任何线程阻塞,直到该对象再次发出信号

  3. This third link说明了这个

      

    事件处于信号状态意味着它有能力释放等待此事件发出信号的线程。事件处于非信号状态意味着它不会释放任何等待此特定事件的线程。

  4. 通过示例对此概念进行简单解释将非常有用。

4 个答案:

答案 0 :(得分:19)

好的,你的3个引号并不相容。但让我们稍微谈谈实施:

每个可等待的对象都附加一个布尔值,命名为信号状态,用于等待该对象;如果对象是信号,那么等待函数将等待它;如果对象是无信令,那么等待函数等待它。

现在,这如何适用于特定类型的对象?这取决于对象的性质,特别是与等待它相关的语义。实际上,信号状态是根据等待条件定义的。例如(有关详细信息,请参阅文档):

  • 当不使用互斥锁时,会发出互斥信号。
  • 完成后会发出进程/线程的信号。
  • 信号量大于0时发出信号。
  • 等待计时器在过期时发出信号。

如果在拥有互联网时发出信号,你可能会更好,但实际上它是在不拥有的时候。这使得等待函数做正确的事情是必要的。

那些事件呢?好吧,它们是一些简单的对象,你可以随意发信号和去信号,所以信号状态没有其他含义:

  • 发出信号:线程不会等待它。
  • 无信号:线程将等待它。

事件也有SignalPulseAutoReset这些有点特殊的东西(而且IME几乎不可能正确使用)。

现在,让我们来看看你的报价:

  

信号状态表示资源可供进程或线程使用。未发信号状态表示资源正在使用中。

实际上,这是一种解释。通常会有一个您尝试仲裁的资源,并且通常您会等待if-only-only - 如果该资源正在使用中,那么它正在使用资源和等待资源之间的等价。但这不是技术要求,只是通常的用例。

  

处于信号状态的对象不会导致等待对象阻塞的线程和未处于信号状态的对象将导致等待该对象的任何线程阻塞,直到该对象再次发出信号

正确而重要!

  

事件处于信号状态意味着它有能力释放等待此事件发出信号的线程。事件处于非信号状态意味着它不会释放任何等待此特定事件的线程。

我发现这个措辞有点令人困惑......但它没有增加前一个措辞。

答案 1 :(得分:10)

简单的思考方式:“发出信号”=“绿灯”

Green Light 如果你正在开车,你看到一个绿灯,你不会停下来(这是一个观察事件的线索,发现它是发出信号并继续进行而没有阻止)。

enter image description here 如果你看到一个红灯你停下来等待它变绿然后继续(知识安全,其他线程现在都没有信号因此等待或将等待他们......红灯!)

答案 2 :(得分:8)

实际上,所有这些解释都是一致的。

事件的最简化(因此不是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
    }
}

不幸的是,由于为降低CPU消耗引入了Sleep调用,这会导致繁忙等待循环中的处理器周期浪费或不必要的延迟执行。两者都是不受欢迎的。

为了避免任务同步的这些问题,操作系统提供不同的标记机制(例如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
        }
    }
}

答案 3 :(得分:0)

我不同意其他答案。他们错过了重点:

  • 如果发出信号的属性为 true =>事件发生在现在之前

  • 如果发出信号的属性为 false => 没有发生直到现在

其中“信号属性为 false ”等于“非信号属性为 true ”。

这三个定义都涉及线程,但不清楚,因为信号定义不是来自多线程而是来自底层编程。

信号来自中断:
如果该信号变高(=中断),则将执行指针移至该函数”。
这就是信号的含义,它来自中断而不是线程。因此,没有信号意味着信号直到现在才变高。

在线程中,它变为: “ 线程需要事件发生才能继续。如果此事件在现在之前发生,它可以继续;否则它将阻塞自身并等待它。”