是否有相当于Windows手动重置事件的UNIX / pthreads?

简而言之,手动重置事件是处于“发信号”或“未发信号”状态的同步构造。 在信号状态下,任何调用事件的等待函数的线程都不会被阻塞,并且执行将不受影响。 任何和所有在非信号对象上调用等待函数的线程都会阻塞,直到事件进入信号状态。

信号状态和非信号状态之间的转换仅发生在显式调用SetEvent和ResetEvent等函数后。

我在Windows上构建了一个同步机制,它使用这些手动重置事件和它们的自动重置兄弟。 自动重置机制可以通过信号量轻松复制,但我正在努力寻找手动重置类型的等价物。

特别是,尽管具有“通知所有”功能的条件变量乍一看可能看起来相似,但在考虑到它需要关联互斥量的事实时,它具有相当不同(可能是非功能性)的行为。 首先,在线程可以等待condvar之前,它必须获得关联的互斥锁。 除了获取和释放互斥锁的代价之外,它还会不必要地序列化所有即将等待的线程。 唤醒后,即使所有线程都被通知,但只有一个线程实际上会一次获得互斥锁,从而导致额外的性能和并发惩罚,因为互斥锁在这种情况下不起任何作用。

考虑到所有等待者的同时释放保证了condvar和Windows事件之间的差异是可观察的,在多CPU系统上的发布情况尤其差,因为在N个线程上的N个线程可以运行在N CPU系统上,并且可以并行运行,而使用condvar - 即使使用避免雷鸣群体的实现 - 线程也只能通过关联的互斥体一次泄漏一个线程。

任何指向更好地模仿手动重置事件行为的构造的指针都将不胜感激。 我能找到的最接近的是一个障碍 - 这允许多线程到屏障的非同步方法和释放 - 但屏障根据等待的线程数而不是显式的应用程序调用“中断”,这正是我所需要的。


它仅限于Linux(我只提到它,因为你有一个“linux”标签),但我认为你可以在futex系统调用上构建这样的东西。 请看Ulrich Drepper关于Futexes的文章,了解更多细节。

非常粗略地说,我设想了一些沿着这条线的东西

void inline gate_wait(volatile int *gate)
{
    if (*gate)
        while (futex(gate, FUTEX_WAIT, 1, 0, 0, 0) == EINTR)
            ;
}

int inline gate_open(volatile int *gate)
{
    *gate = 0;
    return futex(gate, FUTEX_WAKE, INT_MAX, 0, 0, 0);
}

void inline gate_close(volatile int *gate)
{
    *gate = 1;
}

如果你确实在futexes之上构建了这个“门”同步原语,那么可能将它贡献给Rusty Russell的用户空间futex库。


如果所有的设置/重置操作都在单线程中,您可以轻松使用管道:当管道为空/非空时,“事件”是非信号/信号的。 要阻塞“事件”,请在管道的读取端使用选择或轮询。 要设置“事件”,在写入结束时写入一个字节。 要重置“事件”,只需通过从读取结束读取字节来清空管道。


读者作家会锁定工作吗? 我怀疑它会这样,但是在你感兴趣的情况下,你必须检查它是否有效。

请参阅http://www.opengroup.org/onlinepubs/000095399/basedefs/pthread.h.html中的rwlock资料

任何数量的阅读器只能使用一个写入器,因此为了阻止其他线程,需要写入锁定。 让他们继续,解锁。 您必须查看哪种情况更有效:在已经有至少一个读锁的情况下获取读锁,或者获取第一个读锁。 我猜测前者,所以让所有线程通过写入 - 解锁后,你可以读取一个锁。

如果你的线程在完成时没有读取 - 解锁,你将不得不做一些不同的事情,或者至少弄乱实现内部。 如果已经累积了2 ^ 31个读锁定,则不需要一次减少一个计数,直到您可以执行写入锁定为止。

哦,是的,咖啡馆的想法解决了这个问题:大门是read_lock; read_unlock; read_lock; read_unlock; 所以你不建立读锁。

链接地址: http://www.djcxy.com/p/43755.html

上一篇: Is there a UNIX/pthreads equivalent to Windows manual reset events?

下一篇: How to extract velocity vectors from dense optical flow?