Possible Duplicate:
Wake up thread blocked on accept() call
我正在编写一个小型服务器,它监听连接(接受它们并将它们传递给工作线程),直到发送自定义停止信号。
如果我使用阻塞套接字,那么我的主接受循环无法在发送自定义停止信号时中断。但是,我希望避免使用非阻塞套接字出现忙等待/自旋锁循环。
我想要的是我的主接受循环阻塞,直到收到连接或发送停止信号。
这在 Linux 上的 C 语言中可能吗?
非常感谢。
最佳答案
如果我理解正确,那么您愿意使用任何类型的“信号”,不一定是 POSIX 信号。实际上,POSIX 信号是一个糟糕的选择,因为检查循环中是否收到信号会不可避免地出现竞争条件。
您需要使用的是任何可以通过文件描述符监视的东西。可能是:
- 一根 pipe 。您的接受循环监视管道的读取端。为了唤醒循环,另一个线程会向写入端写入一些内容(不管是什么)。
- 另一个套接字。同样,另一个线程通过写入套接字的另一端来唤醒您的接受循环。
- 文件系统中使用 inotify 监控的文件。
- 当循环应该中断时接收一些数据的设备。
- 等等...
示例列表中后面的条目通常不实用。它们只是为了说明它可以是任何类型的对象,只要它具有可监视的文件描述符即可。最简单、最便宜、最流行的方式是管道。
如果您已经在使用非阻塞套接字,那么您肯定已经有了某种轮询循环来检查它们何时准备好接受连接。我假设您使用 poll()
来执行此操作。
在开始循环之前,设置一个管道,如下所示:
pipe(&pipefd[0]);
read_end = pipefd[0];
write_end = pipefd[1];
fcntl(read_end, F_SETFL, O_NONBLOCK);
fcntl
是将管道的读端设置为非阻塞模式。您将在 poll
调用中与套接字一起使用管道的一端,因此它需要是非阻塞的。
然后只需将管道的读取端添加到您在接受循环中监视的图 block 描述符列表中即可:
for (;;) { /* accept loop, loop forever */
/* Monitor your socket. You should already have this in your code */
pollfd[0].fd = your_socket;
pollfd[1].events = POLLIN;
/* Add a new entry to monitor the read end of the pipe */
pollfd[1].fd = read_end;
pollfd[1].events = POLLIN;
/* Now call poll, as before, but monitor 2 file descriptors instead of just 1 */
n = poll(&pollfd[0], 2, -1);
/* Check if your socket is ready to accept.
This part, you are already doing. */
if (pollfd[0].revents) {
newsocket = accept(your_socket, etc....)
do_somehting_with(new_socket);
}
/* New part: check if anyone has written something for you into your pipe */
if (pollfd[1].revents) {
break; /* stop the loop */
}
}
该示例使用poll
,但您可能会使用select
(甚至epoll
)。 select
有不同的界面,但想法是相同的。
该技术被称为 self-pipe trick .
关于c - C 中无自旋锁的非阻塞套接字接受,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13323279/