【发布时间】:2014-03-20 12:06:03
【问题描述】:
我正在编写一个小型服务器,它将接收来自多个来源的数据并处理这些数据。收到的来源和数据很重要,但不超过epoll应该能够很好地处理。但是,所有接收到的数据都必须进行解析并通过大量测试运行,这既耗时又会阻塞单个线程,尽管 epoll 多路复用。基本上,该模式应该如下所示:IO-loop 接收数据并将其捆绑到作业中,发送到池中的第一个可用线程,捆绑由作业处理并将结果传递到 IO 循环中写入文件。
我决定使用单个 IO 线程和 N 个工作线程。用于接受 tcp 连接和读取数据的 IO 线程使用以下提供的示例很容易实现: http://linux.die.net/man/7/epoll
线程通常也很容易处理,但我正在努力以一种优雅的方式将 epoll IO 循环与线程池结合起来。我也找不到任何将 epoll 与在线工作池一起使用的“最佳实践”,但是关于同一主题的问题很多。
因此我有一些问题希望有人能帮助我回答:
- 是否可以(并且应该)使用 eventfd 作为 IO 线程和所有工作线程之间双向同步的机制?例如,每个工作线程都有自己的 epoll 例程等待共享 eventfd(带有结构指针,包含有关作业的数据/信息),即以某种方式使用 eventfd 作为作业队列,这是一个好主意吗?或许还有另一个 eventfd 将结果从多个工作线程传回 IO 线程?
- 在 IO 线程收到有关套接字上更多数据的信号后,是否应该在 IO 线程上进行实际的接收,或者工作人员是否应该自己接收数据,以便在解析数据帧时不阻塞 IO 线程等.?在那种情况下,我怎样才能确保安全,例如如果 recv 在一个工作线程中读取 1.5 帧数据,而另一个工作线程从同一连接接收最后 0.5 帧数据?
- 如果工作线程池是通过互斥锁等实现的,如果N+1个线程尝试使用同一个锁,等待锁会阻塞IO线程吗?
- 对于如何通过双向通信(即从 IO 到 worker 和返回)围绕 epoll 构建工作线程池,是否有任何好的实践模式?
编辑:一个可能的解决方案是从 IO 循环更新环形缓冲区,更新后通过所有工作人员的共享管道将环形缓冲区索引发送给工作人员(从而将该索引的控制权交给第一个工作人员从管道中读取索引),让工作人员拥有该索引直到处理结束,然后再次通过管道将索引号发送回 IO 线程,从而交还控制权?
我的应用程序仅适用于 Linux,因此我可以使用仅适用于 Linux 的功能,以便以最优雅的方式实现这一目标。不需要跨平台支持,但需要性能和线程安全。
【问题讨论】:
-
我想我可能有一个有用的解决方案,但需要知道,你多久知道单个帧/数据包的长度?它们是固定长度,是包含在数据包头中还是您只知道最后?如果你早点知道,那么在不忙于主线程的情况下完成工作要容易得多,但如果你不知道到最后,主线程不可避免地需要做大量的阅读。
-
嗨,我知道 recv 之后和遍历 recv 缓冲区之后的长度。不幸的是,它们不是固定长度,并且长度不会出现在数据包中,而是基于换行帧。
标签: c linux multithreading posix epoll