一連のネットワーク接続にデータを送信する 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
}
実際にはそれよりもはるかに複雑ですが、多くの不要な詳細を削除しました。重要な詳細の 1 つは、ネットワークがレート制限されていることと、プログラムがデータを送信するのとは別にキューに入れる機能が設計の特徴であることです (プログラムはネットワーク書き込みでブロックされているため、新しいデータの処理を待つ必要はありません)。 )。
以下は、プログラムがこのクラスとどのように対話することが期待されるかについての簡単な説明です。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 ヘッダーをコードに取り込むと、コンパイルに耐えられないほど時間がかかります。