web-dev-qa-db-ja.com

プログラムがスレッドを使用するかどうかを推測する

スレッドセーフまたはスレッド互換のコードが適しています。ただし、プログラムがスレッドを使用しないことがわかっている場合は、別の方法で(より単純に、またはより効率的に)実装できる場合があります。

たとえば、std::shared_ptrのようなものは、スレッド化されていないケースを最適化するために異なる実装を使用できると聞いたことがあります(ただし、参照が見つかりません)。歴史的には、一部の実装ではstd::stringが非スレッドコードでコピーオンライトを使用できると思います。

私はこれらの手法に賛成でも反対でもありませんが、コードがコンパイルされているかどうかをコンパイル時に決定する方法(少なくとも名目上の方法)があるかどうか知りたいですスレッドを使用する意図

私が得ることができる最も近いのは、スレッド化されたコードが通常(?)-pthreads(ではなく-lpthreads)コンパイラー・オプションでコンパイルされていることを理解することです。 (それが難しい要件なのか、それとも単に推奨されるのかはわかりません。)

次に、-pthreadsは、少なくともgccclangで、_REENTRANTまたは_THREAD_SAFEなどのマクロを定義します。 SOの一部の 一部の回答 では、廃止されていることも読みました。

これらのマクロは、プログラムがスレッドで使用されることが意図されているかどうかを判断する正しい方法ですか? (例えば、同じプログラムから起動されたスレッド)。コンパイル時にこれを検出する他のメカニズムはありますか?検出方法はどの程度信頼できますか?


編集:質問は明らかに多くのコンテキストに適用できるため、具体的なケースを挙げましょう:

内部で別のサードパーティライブラリを使用するヘッダーのみのライブラリを作成しています。ライブラリをスレッドセーフに初期化する必要があるかどうか(または、少なくとも特定のレベルのスレッドサポートを提供する必要があるかどうか)を知りたいです。最大レベルのスレッドサポートを想定しているが、ライブラリのユーザーがスレッドを使用しない場合、無料で費用が発生します。 3番目のライブラリは実装の詳細なので、私は推測に基づいて要求されたスレッドセーフティのレベルを決定することができました。

3
alfC

スレッドセーフの決定は理想的にはプログラム全体で行われるべきではなく、特定の領域に対して行われるべきであるという点で、私は他の答えを支持します。

boost::shared_ptrには、boost::local_shared_ptrと呼ばれるスレッドセーフでないバージョンがあることに注意してください。 boost::intrusive_ptrには、安全および危険なカウンター実装があります。

一部のライブラリは、「null mutex」パターンを使用します。これは、lock/unlockに対して何もしないミューテックスです。 boostまたはIntel TBB null_mutex、またはATL CComFakeCriticalSectionを参照してください。これは具体的には、実際のミューテックスをthreqadセーフコードに置き換え、偽のミューテックスをスレッドセーフでないコードに置き換えることです。

さらに、現在の実行フェーズによっては、同じオブジェクトをスレッドセーフな方法とスレッドアンセーフな方法で使用することが理にかなっている場合があります。 atomic_refもあります。これは、基になる型へのスレッドセーフなアクセスを提供する目的で機能しますが、スレッドセーフではない型での操作を許可します。

ランタイムがスレッドセーフとスレッドアンセーフを切り替える良い例を知っています。 HeapCreateHEAP_NO_SERIALIZE、およびHeapAllocHEAP_NO_SERIALIZEを参照してください。

同じことの疑わしい例も知っています。 Delphiでは、BeginThread AP​​I関数ではなく、そのCreateThreadラッパーを呼び出すことをお勧めします。ラッパーはグローバル変数を設定して、Delphiのメモリマネージャーはスレッドセーフであることを通知します。この動作がまだ適切であるかどうかはわかりませんが、Delphi 7にはありました。


おもしろい事実:Windows 10では、シングルスレッドプログラムは事実上ありません。 mainの最初のステートメントが実行される前に、静的DLL依存関係がロードされます。現在のWindowsバージョンでは、これを使用して、可能な場合は次のようにロードを並列化しますDLLスレッドプール。プログラムが読み込まれると、スレッドプールスレッドは、Windows API呼び出しまたはstd::asyncを使用して発行される可能性のある他のタスクを待機します。プログラム自体がスレッドとTLSを使用しない場合は、通知されません。しかし、技術的には、OSの観点からはマルチスレッドです。

1
Alex Guteniev