有没有办法阻止单个线程直到信号量或输入事件?

时间:2014-09-30 08:33:33

标签: c++ c windows multithreading sockets

我打算编写一个程序来处理来自TCP / IP连接和来自共享内存队列的请求。这意味着程序应该阻塞,直到队列中有请求或套接字上有输入。然后它将处理请求并继续。有没有办法在单个线程中执行此操作?我的意思是某种select同时使用信号量和套接字。在我的情况下,延迟很重要,我也不想做一个忙碌的等待。该程序将在Windows上运行。感谢。

3 个答案:

答案 0 :(得分:3)

一种方法是使用重叠I / O并使用hEvent机制来发出I / O完成信号。然后,您可以使用hEvent API等待队列信号量和WaitForMultipleObjects() / s。

另一种方法是使用重叠的I / O和完成例程。然后,您可以在WaitForSingleObectEx() API的循环中等待信号量,并将bAlertable参数设置为true,以便线程可以处理排队的完成例程,例如:

while(WAIT_IO_COMPLETION!=WaitForSingleObjectEx(queueSema,INFINITE,true)){
  [deque object and handle it];
};

这两种方案都允许您设置超时以轮询服务器以保持连接打开和/或检查它是否已关闭。

答案 1 :(得分:2)

Libevent是一种抽象I / O事件的方法,它有一种手动触发事件的方法。

使用libevents设置基于文件的事件如下所示(从文档中复制):

void callback_func(evutil_socket_t fd, short what, void *arg) { ... }

struct event *ev1, *ev2;
struct event_base *base = event_base_new();

/* The caller has already set up fd1, fd2 somehow, and make them
   nonblocking. */

ev1 = event_new(base, fd1, EV_TIMEOUT|EV_READ|EV_PERSIST, callback_func,
   (char*)"Reading event");
ev2 = event_new(base, fd2, EV_WRITE|EV_PERSIST, callback_func,
   (char*)"Writing event");

event_add(ev1, NULL);
event_add(ev2, NULL);

如果要创建与任何文件描述符无关的事件,请传递fd的-1符号:

ev = event_new(base, -1, EV_PERSIST | EV_READ, callback_func, NULL);
event_add(ev, NULL);

现在,不是提高信号量,而是触发事件:

event_active(ev, EV_WRITE, 0);

答案 2 :(得分:1)

Windows等待几种可能发生的事情之一的方式是WaitForMultipleObjectsEx。你给它一组Windows"处理"这可以成为"发出信号" (这些类型的句柄称为同步对象),当它们中的任何一个被发出信号时,该函数返回并告诉你它是哪一个。

问题是,在WinSock库中实现的套接字不是Windows句柄。您无法将其放入WaitForMultipleObjectsEx数组中。

幸运的是,WinSock提供了一个函数WSAEventSelect,它可以将套接字链接到Windows事件对象。事件对象是最简单的同步对象类型。在这种情况下,当套接字准备好被读取时,你会要求它发出事件对象的信号(FD_READ)。然后你将事件对象放在信号量旁边的数组中。

Windows信号量已经是同步对象 - 请参阅MSDN中的CreateSemaphore。当计数大于0时,它会发出信号。(这是您对信号量的期望。)

如果您不了解同步对象的全部概念并且阅读MSDN没有帮助,我建议Jim Beveridge的书 Win32中的多线程应用程序。它是一本旧书,因此它没有套接字或信号量,但它解释了如何使用事件对象,互斥体和WaitForMultipleObjects。那么套接字和信号量很容易理解。