私はほとんどの場合、もっぱらマルチスレッドの高性能な世界で開発を行っているので、私が使用する一般的な方法を次に示します。
設計 - 最良の最適化はより優れたアルゴリズムです:
1)機能を論理的に分離可能な部分に分割します。
これは、呼び出しが「A」と「A」のみを実行することを意味します-A、B、C ではなく... 副作用を完全になくすことができない場合は、副作用をいくつかの場所に分離します (コードに集中させます)。
3) できるだけ多くの分離されたコンポーネントを RE-ENTRANT にします。これは、ステートレスであることを意味します。すべての入力を定数として受け取り、宣言された論理定数パラメーターのみを操作して出力を生成します。可能な限り、参照ではなく値渡し。
4) ステートがある場合は、ステートレス サブアセンブリと実際のステート マシンを明確に分離します。ステート マシンは、ステートレス コンポーネントを操作する単一の関数またはクラスであることが理想的です。
デバッグ:
スレッディングのバグは、競合とデッドロックという 2 つの広範なフレーバーで発生する傾向があります。原則として、デッドロックははるかに決定論的です。
1) データの破損が見られますか?: はい => おそらく競合です。
2) バグはすべての実行で発生しますか、それとも一部の実行で発生しますか?: はい => デッドロックの可能性があります (レースは一般的に非決定論的です)。
3) プロセスがハングすることはありますか?: はい => どこかでデッドロックが発生しています。たまにしかハングしない場合は、競合も発生している可能性があります。
ブレークポイントは、コード内の同期プリミティブ THEMSELVES のように動作することがよくあります。これは、論理的に類似しているためです。他のコンテキスト (ユーザー) が再開する信号を送信するまで、現在のコンテキストで強制的に実行を停止させます。これは、マルチスレッドの動作を変更するものとしてコード内にあるブレークポイントを表示する必要があることを意味します。ブレークポイントは競合状態に影響しますが、(一般に) デッドロックには影響しません。
原則として、これは、すべてのブレークポイントを削除し、バグの種類を特定してから、それらを再導入して修正する必要があることを意味します。そうでなければ、物事をさらに歪めるだけです。