假设我有两个库(A和B),每个库都有一个侦听套接字的函数。这些函数使用select(),如果数据已经到达,它们会立即返回一些事件,否则它们会等待一段时间( timeout )然后返回NULL:
A_event_t* A_wait_for_event(int timeout);
B_event_t* B_wait_for_event(int timeout);
现在,我在我的程序中使用它们:
int main (int argc, char *argv[]) {
// Init A
// Init B
// .. do some other initialization
A_event_t *evA;
B_event_t *evB;
for(;;) {
evA = A_wait_for_event(50);
evB = B_wait_for_event(50);
// do some work based on events
}
}
每个库都有自己的套接字(例如udp套接字),无法从外部访问。
问题:效率不高。例如,如果有很多事件等待由* B_wait_for_event *传递,则这些事件必须始终等待* A_wait_for_event *超时,这有效地限制了库B和我的程序的吞吐量。
通常,可以使用线程来分离处理,但是如果某些事件的处理需要调用其他库的功能,反之亦然。例如:
if (evA != 0 && evA == A_EVENT_1) {
B_do_something();
}
if (evB != 0 && evB == B_EVENT_C) {
A_do_something();
}
因此,即使我可以创建两个线程并从库中分离功能,这些线程也必须在它们之间交换事件(可能通过管道)。这仍然会限制性能,因为* X_wait_for_event()*函数会阻塞一个线程,并且无法立即从其他线程接收数据。
如何解决这个问题?
答案 0 :(得分:3)
根据您使用的库,此解决方案可能不可用,但最佳解决方案是 来调用等待事件的各个库中的函数。每个库都应该支持挂钩到外部事件循环。然后,您的应用程序使用单个循环,其中包含poll()
或select()
调用,该调用等待您使用的所有库都要等待的所有事件。
glib's event loop对此有好处,因为许多库已经知道如何挂钩它。但是如果你不使用像glib那样复杂的东西,通常的做法就是:
poll()
poll()
返回时可能发生的任何事件。是的,早期的图书馆仍有可能使后来的图书馆挨饿,但它在实践中有效。
如果您使用的库不支持此类设置&调度接口,将其添加为功能并在上游提供代码!
答案 1 :(得分:2)
(我正在回答这个问题,因为评论的时间太长了)
如果您处于这样的情况:当另一个线程正在执行时A_do_something
(同样对于A_wait_for_event
),您不允许在一个线程中调用B
,那么我就是很确定你不能做任何有效的事情,并且必须在各种邪恶之间解决。
最明显的改进是立即采取行动,而不是试图从两者中读取:即命令你的循环
你可以做的其他缓解措施
编辑:您可以检查您的库的API;他们可能已经提供了解决问题的方法。例如,它们可能允许您注册事件的回调,并通过回调获取事件通知,而不是轮询wait_for_event
。
另一件事是,如果您可以为要监听的库创建新的文件描述符。例如如果您创建一个新管道并将一端交给库A
,那么如果线程#1正在等待A
事件,则线程#2可以写入管道以使事件发生,从而强制执行wait_for_event
中排名第一。能够随意将线程踢出wait_for_event
函数,可以使用各种新选项。
答案 2 :(得分:1)
一种可能的解决方案是在“主”线程中使用两个线程到wait_for_events
加boost::condition_variable
“做某事”。 here