代码之家  ›  专栏  ›  技术社区  ›  Sergey Kurenkov

如何在Windows上的select()中取消等待

  •  6
  • Sergey Kurenkov  · 技术社区  · 14 年前

    在我的程序中,有一个线程(接收线程)负责接收来自TCP套接字的请求,还有许多线程(工作线程)负责处理接收到的请求。一旦处理了一个请求,我需要通过TCP发送一个应答。

    这里有一个问题。我想在我用来接收数据的同一个线程中发送TCP数据。此线程在接收数据后通常在 select() . 因此,一旦一个工作线程完成了一个请求的处理并在输出队列中放置了一个答案,它就必须向接收线程发出信号,表明有数据要发送。问题是我不知道如何取消等待 选择() 为了摆脱等待和呼叫 send() .

    或者我应该只使用另一个线程通过TCP发送数据吗?

    更新的

    阿托姆,改变女士,谢谢你的回答!

    msalters,在阅读了你的答案后,我找到了这个网站: Winsock 2 I/O Methods 阅读有关 WSAWaitForMultipleEvents() . 事实上,我的程序必须同时在HP-UX和Windows上运行,我最终决定使用Artyom建议的方法。

    5 回复  |  直到 12 年前
        1
  •  15
  •   Artyom    14 年前

    您需要使用类似于安全管道技巧的东西,但在您的情况下,您需要使用一对连接的TCP套接字。

    1. 创建一对套接字。
    2. 将一个添加到选择中并等待它
    3. 通过从其他线程写入其他套接字来通知。
    4. 选择将立即唤醒,因为其中一个套接字是可读的,读取所有 此特殊套接字中的数据,并检查要发送/接收的队列中的所有数据

    如何在Windows下创建一对套接字?

    inline void pair(SOCKET fds[2])
    {
        struct sockaddr_in inaddr;
        struct sockaddr addr;
        SOCKET lst=::socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
        memset(&inaddr, 0, sizeof(inaddr));
        memset(&addr, 0, sizeof(addr));
        inaddr.sin_family = AF_INET;
        inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
        inaddr.sin_port = 0;
        int yes=1;
        setsockopt(lst,SOL_SOCKET,SO_REUSEADDR,(char*)&yes,sizeof(yes));
        bind(lst,(struct sockaddr *)&inaddr,sizeof(inaddr));
        listen(lst,1);
        int len=sizeof(inaddr);
        getsockname(lst, &addr,&len);
        fds[0]=::socket(AF_INET, SOCK_STREAM,0);
        connect(fds[0],&addr,len);
        fds[1]=accept(lst,0,0);
        closesocket(lst);
    }
    

    当然,应该为返回值添加一些检查。

        2
  •  7
  •   MSalters    14 年前

    select 不是Windows的本机API。本地方式是 WSAWaitForMultipleEvents . 如果您使用此选项创建可提醒的等待,则可以使用 QueueUserAPC 指示等待线程发送数据。(这也可能意味着您不必实现自己的输出队列)

        3
  •  4
  •   Community CDub    7 年前

    另见本帖: How to signal select() to return immediately?

    对于UNIX,使用匿名管道。对于Windows: 解除阻塞可以通过向fd_集添加一个虚拟(未绑定)数据报套接字,然后关闭它来实现。要使此线程安全,请使用queueuserapc:

    我找到的使这个多线程安全的唯一方法是在运行select语句的同一线程中关闭并重新创建套接字。当然,如果线程在select上阻塞,这是很困难的。然后在Windows中调用queueuserapc。当Windows在select语句中阻塞时,线程可以处理异步过程调用。您可以使用queueuserapc从不同的线程调度它。Windows中断select,在同一线程中执行函数,并继续使用select语句。现在您可以在APC方法中关闭套接字并重新创建它。保证线程安全,您永远不会释放信号。

        4
  •  0
  •   sarnold    14 年前

    典型的模式是让工人处理自己的写作。是否有原因要通过发送所有输出IO select 线程?

    如果您确定这个模型,您也可以让您的工作人员使用文件描述符将数据发送回主线程。( pipe(2) )只需将这些描述符添加到 select() 打电话。

    而且,如果您特别确定不会使用管道将数据发送回主进程,那么 选择 调用允许您指定超时。您可以在检查工作线程时忙着等待,并定期调用 选择 找出要读取的TCP套接字。

        5
  •  0
  •   MSalters    14 年前

    另一个快速而肮脏的解决方案是向集合中添加本地主机套接字。现在使用这些套接字作为线程间通信队列。每个工作线程只向其套接字发送一些内容,这些内容最终到达接收线程中相应的套接字。这唤醒了 select() 然后,您的接收线程可以在适当的传出套接字上回显消息。