2

我正在使用 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_tpthread_mutex_tpthread_cond_tsem_t),我不关心与 Windows 的兼容性。另外,请不要推荐Boost。将任何 Boost 标头拉入我的代码会使编译时间过长。

4

0 回答 0