在套接字关闭时取消阻止recvfrom

use*_*178 7 c sockets select recv

假设我开始在端口上接收一个线程.套接字调用将阻止recvfrom.然后,不知何故在另一个线程中,我关闭套接字.

在Windows上,这将取消阻止recvfrom,我的线程执行将终止.

在Linux上,这不会解锁recvfrom,因此,我的线程永远不会做任何事情,并且线程执行不会终止.

任何人都可以帮助我解决Linux上发生的事情吗?当套接字关闭时,我希望recvfrom解除阻塞

我一直在阅读有关使用select()的内容,但我不知道如何在特定情况下使用它.

小智 13

调用shutdown(sock, SHUT_RDWR)套接字,然后等待线程退出.(即pthread_join).

你会认为这close()会解锁recvfrom(),但它不会在Linux上.

  • 它不是,也不可能保证在*任何*系统上解除对`recvfrom`的阻止。有一个固有的竞争只能通过用户空间的同步来解决。 (2认同)

Jer*_*ner 6

下面是一个使用 select() 来处理这个问题的简单方法的草图:

// Note: untested code, may contain typos or bugs
static volatile bool _threadGoAway = false;

void MyThread(void *)
{
   int fd = (your socket fd);
   while(1)
   {
      struct timeval timeout = {1, 0};  // make select() return once per second

      fd_set readSet;
      FD_ZERO(&readSet);
      FD_SET(fd, &readSet);

      if (select(fd+1, &readSet, NULL, NULL, &timeout) >= 0)
      {
         if (_threadGoAway)
         {
            printf("MyThread:  main thread wants me to scram, bye bye!\n");
            return;
         }
         else if (FD_ISSET(fd, &readSet))
         {
            char buf[1024];
            int numBytes = recvfrom(fd, buf, sizeof(buf), 0);
            [...handle the received bytes here...]
         }
      }
      else perror("select");
   }
}

// To be called by the main thread at shutdown time
void MakeTheReadThreadGoAway()
{
   _threadGoAway = true;
   (void) pthread_join(_thread, NULL);   // may block for up to one second
}
Run Code Online (Sandbox Code Playgroud)

一个更优雅的方法是避免使用 select 的超时功能,而是创建一个套接字对(使用 socketpair())并让主线程在需要 I/O 线程时在它的套接字对的末尾发送一个字节离开,并在 I/O 线程在套接字对另一端的套接字上接收到一个字节时退出。不过,我会将其作为练习留给读者。:)

将套接字设置为非阻塞模式通常也是一个好主意,以避免即使在 select() 指示套接字已准备好读取之后 recvfrom() 调用也可能阻塞的(小但非零)机会,如所描述这里。但是阻塞模式对于您的目的来说可能“足够好”。


Chr*_*odd 4

不是答案,但 Linux close 手册页包含有趣的引用:

当同一进程中的其他线程中的系统调用可能正在使用文件描述符时,关闭它们可能是不明智的。由于文件描述符可以重复使用,因此存在一些模糊的竞争条件,可能会导致意想不到的副作用。