将windows手动重置事件移植到Linux?

13 linux windows multithreading pthreads

如果设置或取消设置事件,是否有更简单的解决方案将窗口手动重置事件移植到pthread,而不是pthread条件变量+ pthread互斥+标记?

eph*_*ent 18

Pthreads是低级构造.不,没有一个更简单的机制; 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);
}
Run Code Online (Sandbox Code Playgroud)

这可能不适合您的使用,因为您通常会使用不同的锁来代替ev->mutex,但这是它通常使用的方法的要点.


小智 7

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

事件处于触发状态 - >有一些东西要从管道中读取

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));
Run Code Online (Sandbox Code Playgroud)

请注意,等待事件不会从管道中读取,因此"事件"将保持在触发状态,直到重置操作.


小智 5

我更喜欢管道方法,因为通常不需要等待的事件,而是多个对象,例如WaitForMultipleObjects(...).并使用管道一个可以很容易地更换窗户WaitForMultipleObjects调用与poll(...),select,pselect,和epoll.

有一种称为Futex(快速用户空间锁定系统调用)的轻量级进程同步方法.有一个函数futex_fd可以为futexes获取一个或多个文件描述符.该文件描述,可能有许多人表示真正的文件,设备,插座或类似在一起可以得到传递给select,pollepoll.不幸的是它已从内核中删除.所以管道技巧仍然是唯一的工具:

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]);
Run Code Online (Sandbox Code Playgroud)