信号和非信号状态的事件

San*_*Pai 12 c winapi multithreading

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

  1. 这个链接表明

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

  2. 我从一个大学网站上得到了一个强力点演示文稿

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

  3. 第三个链接说明了这一点

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

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

rod*_*igo 20

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

每个可等待的对象都附加一个布尔值,命名为信号状态,用于等待该对象; 如果对象发出信号,则等待函数不会等待它; 如果对象是非信号的,那么等待函数等待它.

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

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

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

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

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

事件也有这个SignalPulseAutoReset有点奇怪的东西(和IME几乎不可能正确使用).

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

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

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

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

正确而重要!

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

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


noe*_*cus 12

简单的想法:"信号"="绿灯"

绿灯 如果你正在开车,你看到一个绿灯,你不会停下来(这是一个看着一个事件的线程,发现它已发出信号并继续进行而没有阻塞).

在此输入图像描述 如果你看到一个红灯你停下来等待它变成绿色然后继续(知识安全,其他线程现在都没有信号因此正在等待或将等待他们......红灯!)


jun*_*nix 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
    }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,由于Sleep为降低CPU消耗而引入的调用,这将导致繁忙等待循环中的处理器周期浪费或不希望的执行延迟.两者都不需要.

为了避免任务同步的这些问题,操作系统提供不同的标志机制(例如Windows中的事件).通过事件,设置和重置标志由OS调用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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)