pthread-like windows手动重置事件

有没有更容易的解决scheme移植到pthread一个Windows手动重置事件,比pthread条件variables+ pthread互斥+标志如果事件设置或取消设置?

Solutions Collecting From Web of "pthread-like windows手动重置事件"

线程是低层次的结构。 不,没有简单的机制; pthread_cond__*在概念上类似于自动重置事件。 要小心, pthread_cond_wait可能有虚假的唤醒,所以不应该在没有某种外部标志的情况下使用,无论情况如何。

但是,建立你自己并不会太难。

 #include <pthread.h> #include <stdbool.h> struct mrevent { pthread_mutex_t mutex; pthread_cond_t cond; bool triggered; }; void mrevent_init(struct mrevent *ev) { pthread_mutex_init(&ev->mutex, 0); pthread_cond_init(&ev->cond, 0); ev->triggered = false; } void mrevent_trigger(struct mrevent *ev) { pthread_mutex_lock(&ev->mutex); ev->triggered = true; pthread_cond_signal(&ev->cond); pthread_mutex_unlock(&ev->mutex); } void mrevent_reset(struct mrevent *ev) { pthread_mutex_lock(&ev->mutex); ev->triggered = false; pthread_mutex_unlock(&ev->mutex); } void mrevent_wait(struct mrevent *ev) { pthread_mutex_lock(&ev->mutex); while (!ev->triggered) pthread_cond_wait(&ev->cond, &ev->mutex); pthread_mutex_unlock(&ev->mutex); } 

这可能不适合你的使用,因为你通常会有一个不同的锁来代替ev->mutex ,但这是它通常使用的要点。

您可以使用管道轻松实现手动重置事件:

事件处于触发状态 – >需要从管道读取数据

SetEvent – > write()

ResetEvent – > read()

WaitForMultipleObjects – > poll()(或select())来读取

为了使管道处于非空状态,“SetEvent”操作应该写一些东西(例如任何值的1个字节),所以后面的“等待”操作,即poll()可用于读取的数据不会被阻塞。

“ResetEvent”操作将读取写入的数据以确保管道再次为空。 管道的读端应该是非阻塞的,所以试图重置(读取)已经重置的事件(空管道)将不会阻塞 – fcntl(pipe_out,F_SETFL,O_NONBLOCK)由于可能有超过1个SetEvents ResetEvent,你应该编码它,以便它读取管道中的字节数:

 char buf[256]; // 256 is arbitrary while( read(pipe_out, buf, sizeof(buf)) == sizeof(buf)); 

请注意,等待事件不会从管道中读取,因此“事件”将保持触发状态,直到复位操作。

不,没有任何简单的解决方案,但下面的代码将做的伎俩:

 void LinuxEvent::wait() { pthread_mutex_lock(&mutex); int signalValue = signalCounter; while (!signaled && signalValue == signalCounter) { pthread_cond_wait(&condition, &mutex); } pthread_mutex_unlock(&mutex); } void LinuxEvent::signal() { pthread_mutex_lock(&mutex); signaled = true; signalCounter++; pthread_cond_broadcast(&condition); pthread_mutex_unlock(&mutex); } void LinuxEvent::reset() { pthread_mutex_lock(&mutex); signaled = false; pthread_mutex_unlock(&mutex); } 

当调用signal()时,事件进入信号状态,所有等待的线程都会运行。 然后事件将保持信号状态,所有的线程调用wait()都不会等待。 reset()的调用将使事件回到无信号状态。

signalCounter是在那里你快速的信号/复位来唤醒等待线程。

我更喜欢管道方式,因为通常不需要等待一个事件,而是多个对象,例如WaitForMultipleObjects(...) 而使用管道可以很容易地用poll(...)selectpselectepoll来代替windows的WaitForMultipleObjects调用。

有一个称为Futex (快速用户空间锁定系统调用)的Futex进程同步方法。 有一个函数futex_fd为futexes获取一个或多个文件描述符。 这个文件描述符,连同可能的许多代表真实文件,设备,套接字等的其他文件可以传递给selectpollepoll 不幸的是,它被从内核中删除 所以管道技巧仍然是唯一的设施:

 int pipefd[2]; char buf[256]; // 256 is arbitrary int r = pipe2(pipefd, O_NONBLOCK); void setEvent() { write(pipefd[1], &buf, 1); } void resetEvent() { while( read(pipefd[0], &buf, sizeof(buf)) > 0 ) {;} } void waitForEvent(int timeoutMS) { struct pollfd fds[1]; fds[0].fd = pipefd[0]; fds[0].events = POLLRDNORM; poll(fds, 1, timeoutMS); } // finalize: close(pipefd[0]); close(pipefd[1]); 

我认为Windows事件更类似于信号量。 即自动重置,你会使用二进制信号和sem_timedwait()函数。

我们正在寻找一种类似的解决方案,将一些大量多线程的C ++代码从Windows移植到Linux,最后编写了一个开源的,MIT授权的Linux库Win32事件 。 它应该是您正在寻找的解决方案,并且经过严格的性能和资源消耗审查。

它实现了手动和自动重置事件,以及WaitForSingleObjectWaitForMultipleObject功能。

我们(全面披露:我在NeoSmart Technologies工作)编写了一个名为pevents的开源(MIT许可)库,它在POSIX上实现了WIN32手动和自动重置事件 ,并包含WaitForSingleObject和WaitForMultipleObjects克隆。 从那以后,它就被采用了(它在Linux / Mac上的Steam中使用)并且工作得很好。

虽然我个人建议你在POSIX机器上编码时使用POSIX多线程和信号范例,但是如果你需要的话,pevents可以给你另一个选择。