我将同时编写一个来自TCP / IP连接和共享内存队列的程序处理请求。 这意味着程序应该阻塞,直到队列中有请求或套接字上有input。 然后它将处理请求并继续。 有没有办法做到这一点在单个线程? 我的意思是某种select
同时使用信号量和套接字。 在我的情况下,延迟是很重要的,我也不想忙于等待。 该程序将在Windows上运行。 谢谢。
等待几种可能发生的事情之一的Windows方式是WaitForMultipleObjectsEx
。 给它一个可以变成“信号”的Windows“句柄”数组(这些句柄称为同步对象),当它们中的任何一个被发信号时,函数返回并告诉你它是哪一个。
问题是,在WinSock库中实现的套接字不是Windows句柄。 你不能把它放到WaitForMultipleObjectsEx
数组中。
幸运的是,WinSock提供了一个函数WSAEventSelect
,可以将套接字链接到Windows事件对象。 事件对象是最简单的同步对象类型。 在这种情况下,当套接字准备被读取( FD_READ
)时,您会要求它发出事件对象的信号。 然后你会把事件对象放到数组旁边。
Windows Semaphore已经是一个同步对象 – 请参阅MSDN中的CreateSemaphore
。 当它的计数大于0时,就会发出信号(这是你所期望的信号量)。
如果你不明白同步对象的整个思想,阅读MSDN没有帮助,我会推荐Jim Beveridge的书在Win32多线程应用程序 。 这是一本老书,所以它没有套接字或信号量,但它解释了如何使用事件对象,互斥体和一般的WaitForMultipleObjects
; 那么socket和信号量就会很容易理解。
一种方法是使用重叠的I / O并使用hEvent
机制来发信号通知I / O完成。 然后,您可以使用WaitForMultipleObjects()
API等待队列信号和hEvent
/ s。
另一种方法是使用重叠的I / O和完成例程。 然后,您可以使用WaitForSingleObectEx()
API在bAlertable
参数设置为true的情况下等待信号量,以便线程可以处理排队的完成例程,例如:
while(WAIT_IO_COMPLETION!=WaitForSingleObjectEx(queueSema,INFINITE,true)){ [deque object and handle it]; };
这两种方案都允许您设置超时轮询服务器以保持连接打开和/或检查是否关闭。
Libevent是一种抽象出I / O事件的方法,它有一种手动触发事件的方法。
使用libevent设置基于文件的事件如下所示(从文档复制):
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:
ev = event_new(base, -1, EV_PERSIST | EV_READ, callback_func, NULL); event_add(ev, NULL);
现在,不是提高信号量,而是触发事件:
event_active(ev, EV_WRITE, 0);