我正在使用 C++ 开发一个多线程项目,该项目将数据发送到一系列网络连接。这是一些伪代码,说明了正在发生的事情:
class NetworkManager
{
Thread writer; // responsible for writing data in queues to the network
Queue[] outqueue; // holds data until the network is ready to receive it
Network[] nets; // sockets or whatever
Mutex[] outlock; // protects access to members of outqueue
Mutex managerlock; // protects access to all queues
Condition notifier; // blocks the write thread when there is no data
}
实际上它比这要复杂得多,但我已经删除了很多不必要的细节。一个重要的细节是网络是有速率限制的,程序独立于发送数据排队的能力是设计的一个特点(程序不应该等待处理新数据,因为它阻塞了网络写入)。
这里简要描述了程序如何与这个类进行交互。请注意,QueueWriteToNetwork
并且DoAdministrativeStuff
在我的实现中,由相同的外部线程管理。
QueueWriteToNetwork(network, data) // responsibility of external thread
Let i = the index of the network to send to
Lock(outlock[i])
outqueue[i].Add(data)
Unlock(outlock[i])
Signal(notifier)
DoAdministrativeStuff(network, more) // responsibility of external thread
Lock(managerlock)
more.Process() // might do any of the following:
// connect or disconnect networks
// add or remove networks from list
// immediate write data to network, bypassing rate limiting
// other things that I forgot
Unlock(managerlock)
WriterThreadMain() // responsibility of internal write thread
Lock(managerlock)
Loop forever:
Check for data in every queue (locking and unlocking each queue)
If all queues have no data to write:
Wait(notifier, managerlock)
continue
If outqueue[i] has data ready to write
Lock(outlock[i])
Send data from outqueue[i]
outqueue[i].Pop()
Unlock(outqueue[i])
正如您可能看到的那样,这种方法存在一些问题(例如,如果写入排队到网络并QueueWriteToNetwork
检查WriterThreadMain
队列是否为空,则调用Signal(notifier)
可能会被丢弃,并且写入队列即使有数据准备好也可以保持等待)。
我需要以这样一种方式来表达这一点,以便以下内容成为可能:
- 将数据添加到写入队列不会阻塞,或者仅在相当短的时间内阻塞(具体来说,它不会在正在进行的网络写入期间阻塞)
- 该
DoAdministrativeStuff
函数必须有能力确保写入线程在安全状态下被阻塞(即不访问任何队列、队列锁或网络)
我已经探索了使用信号量来跟踪写入队列中的项目数的可能性。这将解决我之前提到的丢失更新问题。
最后,我的目标是 Linux(使用 Posix 库来提供类型pthread_t
、pthread_mutex_t
、pthread_cond_t
和sem_t
),我不关心与 Windows 的兼容性。另外,请不要推荐Boost。将任何 Boost 标头拉入我的代码会使编译时间过长。