程式語言 - GNU - C/C++ - Event



參考資料:
https://stackoverflow.com/questions/77905421/linux-how-to-wait-on-event-without-using-mutex

main.c

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <poll.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/eventfd.h>

static int create_event(bool state)
{
    return eventfd(state ? 1 : 0, EFD_CLOEXEC | EFD_NONBLOCK);
}

static bool reset_event(int fd)
{
    uint64_t dummy = 0;
    ssize_t r = read(fd, &dummy, sizeof(dummy));

    if ((r < 0) && (errno != EAGAIN)) {
        return false;
    }

    return true;
}

static bool set_event(int fd)
{
    uint64_t dummy = 1;
    ssize_t r = write(fd, &dummy, sizeof(dummy));

    if (r < 0) {
        return false;
    }
    return true;
}

// timeout < 0: infinite
// timeout > 0: timeout in ms
// timeout = 0: just checks if event was set
static bool wait_for_event(int fd, int timeout)
{
    int rc = -1;
    errno = EINTR;
    struct pollfd pfd = { 0 };

    do {
        pfd.fd = fd;
        pfd.events = POLLIN;
        pfd.revents = 0;
        rc = poll(&pfd, 1, timeout);
    } while ((rc < 0) && (errno == EINTR));

    if (rc < 0) {
        return false;
    }

    if ((rc == 0) || !(pfd.revents & POLLIN)) {
        errno = 0;
        return false;
    }
    return true;
}

static void* mythread(void *param)
{
    printf("mythread++\n");

    printf("wait for 1s...\n");
    usleep(1000000);

    printf("set event\n");
    set_event((uintptr_t)param);

    printf("mythread--\n");

    return NULL;
}

int main(int argc, char *argv[])
{
    bool r = false;
    int event = -1;
    pthread_t thread_id = 0;

    event = create_event(false);
    pthread_create(&thread_id, NULL, mythread, (void *)(uintptr_t)event);

    r = wait_for_event(event, -1);
    printf("wait for event (r=%d)\n", r);

    reset_event(event);
    r = wait_for_event(event, 0);
    printf("query event: (r=%d)\n", r);

    pthread_join(thread_id, NULL);
    close(event);

    return 0;
}

編譯、執行

$ gcc main.c -o main
$ ./main
    mythread++
    wait for 1s...
    set event
    mythread--
    wait for event (r=1)
    query event: (r=0)