我正在写一个POSIX兼容的多线程服务器在C/C + +必须能够接受,读取和写入大量连接异步。服务器有几个工作线程执行任务,偶尔(不可预知地)将队列数据写入套接字。数据偶尔(不可预知地)被客户端写入套接字,所以服务器也必须异步读取。这样做的一个显而易见的方法是为每个连接提供一个线程,以便从其socket读写数据;但这很丑陋,因为每个连接可能会持续很长时间,因此服务器可能不得不保持数百或数千个线程来跟踪连接。等待条件(pthread_cond_wait)和套接字更改(选择)
更好的方法是使用select()/ pselect()函数处理所有通信的单个线程。也就是说,单个线程在任何套接字上等待可读,然后产生一个作业来处理输入,只要输入可用,该输入将由其他线程池处理。每当其他工作线程产生连接输出时,它就会排队,并且通信线程在写入之前等待该套接字可写。
问题在于,当输出由服务器的工作线程排队时,通信线程可能正在select()或pselect()函数中等待。可能的是,如果没有输入到达几秒或几分钟,则排队的输出块将等待通信线程完成select()。这不应该发生,但是 - 应尽快写入数据。
现在我看到一些对线程安全的解决方案。一个是让通信线程忙 - 等待输入并更新它每隔十分之一秒等待写入的套接字列表。这不是最佳的,因为它涉及到忙等待,但它会起作用。另一种方法是在新输出排队时使用pselect()并发送USR1信号(或类似的东西),以允许通信线程立即更新正在等待可写状态的套接字列表。我更喜欢后者,但仍然不喜欢使用信号来表示应该成为条件的东西(pthread_cond_t)。还有一种选择是在select()正在等待的文件描述符列表中包含一个虚拟文件,当我们需要将套接字添加到select()的可写fd_set中时,我们会写入一个单独的字节;这会唤醒通信服务器,因为该特定的虚拟文件会被读取,从而允许通信线程立即更新它的可写fd_set。我觉得第二种方法(使用信号)是编程服务器的“最正确”方式,但我很好奇,如果有人知道上述哪一种方法是最高效的,一般来说,上述任何一种情况是否会导致我不知道的竞争条件,或者是否有人知道这个问题的更一般的解决方案。我真正想要的是一个pthread_cond_wait_and_select()函数,它允许comm线程等待套接字中的变化或来自条件的信号。
在此先感谢。