在一个线程上使用 ppoll 阻塞并在另一个线程上读取/写入相同的 fds 是否安全

Is it safe to block with ppoll on one thread, and read/write to the same fds on another?

本文关键字:线程 安全 读取 另一个 是否 fds 一个 ppoll      更新时间:2023-10-16

我正在设计一个程序(C++11,针对Linux,如果重要的话,则针对CentOS 7),其中一个线程将调用ppoll来阻止多个fds,而这些fds的任何读取/写入都将在其他线程上进行。所有这些 fd 都将设置为非阻塞。

当然,我的问题是,我是否需要确保任何特定的 fd 在用于读取/写入时不会被轮询,或者不为此进行任何并发检查是否安全?

select 的

手册页提到了在轮询时关闭 fd 的多线程问题,但没有提到读/写,轮询和其他相关函数只是引用 select。所以我假设没有问题,但我正在寻找一个明确的来源,比如一个标准,说是的,它是安全的,或者不,它不是。

选择和轮询方法不是线程安全的。如果你想要一个线程安全的替代方案,你应该看看 epoll .除了 MT,对于大型文件描述符集来说,它的速度更快。epoll 方法让内核负责管理 fd 集,这保证了你可以等待具有多个线程的同一集。

假设您在线程中收到一个 POLLOUT 事件,并将该事件排队等待另一个线程处理它,则轮询/选择将继续立即返回,直到处理线程完成对 POLLOUT 事件的处理。

使用内核方法轮询多个事件在很大程度上取决于平台。尽管类 UNIX 系统具有类似的方法,但它们根本不是可移植的。

我在一个线程中的多个 fds 上使用 poll(),而另一个线程在这些 fds 上读取或写入......当另一个线程写入它时,您将获得事件 POLLIN....当其中一个 fds 关闭时,您将获得一个 POLLNVAL.So,您的线程解封,您可以检查哪个 fd 导致了它,将其从您正在轮询的 fds 集中删除,然后继续使用新的文件描述符集进行轮询。

struct pollfd *fds
struct pollfd {
    int   fd;         /* file descriptor */
    short events;     /* requested events */
    short revents;    /* returned events */
};

您可以通过上述结构检查数据。

另一方面,如果要在关闭特定文件描述符之前取消阻止轮询线程,并且不想轮询它,则可以使用 pipe[]。管道会给你两个fd的读写fd。您可以将管道的读取端添加到轮询线程的 fdset,并使用来自其他线程的写入端作为信号机制来取消阻止轮询线程并在需要时操作 pollfdset。