c - C 中无自旋锁的非阻塞套接字接受

标签 c sockets signals nonblocking spinlock

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/

相关文章:

c - recv() 在多线程环境中不会被信号中断

signals - 在信号 ocaml 上转储线程堆栈

c - 变量声明很昂贵吗?

c++ - 套接字内存泄漏

c - 程序无故结束(C语言)

java - 从 AKKA 等 Actor 模型框架调用基于线程的 API

python - 如何在日志配置文件中引用标准库?

c++ - 为什么 "find usage"不适用于不同子项目中的信号

c++ - 为什么 gcc 和 NVCC (g++) 看到两种不同的结构大小?

c - 减去十六进制