4

最近、スタック内のメモリは他のスレッドと共有されておらず、ヒープ内のメモリは他のスレッドと共有されていると聞きました。

私は通常行います:

HWND otherThreadHwnd;
DWORD commandId;
// initialize commandId and otherThreadHwnd

struct MyData {
  int data1_;
  long data2_;
  void* chunk_;
};

int abc() {
  MyData myData;
  // initialize myData
  SendMessage(otherThreadHwnd,commandId,&myData);
  // read myData
}

これをしてもいいですか?

4

5 に答える 5

3

はい、この場合は安全です。

スタック上のデータは、関数呼び出しの存続期間中のみ存在します。SendMessage は同期のブロック呼び出しであるため、データはその呼び出しの間有効です。

SendMessage を PostMessage、SendNotifyMessage、または SendMessageCallback の呼び出しに置き換えると、このコードは壊れます。これらはブロックされず、ターゲット ウィンドウがメッセージを受信する前に関数が返される可能性があるためです。

于 2010-02-11T02:15:56.637 に答える
2

「スタック内のメモリが他のスレッドと共有されていないと聞いた」人は、2つの異なる問題が混乱していると思います。

  1. オブジェクトの有効期間 - スタック上のデータは、スレッドが変数の名前のスコープを離れない限り有効です。あなたの例では、他のスレッドを同期的に呼び出すことでこれを処理しています。

  2. メモリ アドレスの可視性 - プロセスのアドレス pspace は、そのプロセス内のさまざまなスレッド間で共有されます。したがって、あるスレッドでアドレス指定可能な変数は、そのプロセス内の他のスレッドでアドレス指定できます。アドレスを別のプロセスのスレッドに渡す場合、状況はまったく異なり、他のメカニズムを使用する必要があります (メモリ ブロックが両方のプロセスにマップされるようにするためかもしれませんが、私はそうしません)。通常、スタックメモリで実行できると思います)。

于 2010-02-11T02:27:13.453 に答える
2

はい、大丈夫です。

SendMessageブロッキング モードで動作しています。がスタックに割り当てられていてもmyData、そのアドレスはプロセス内のすべてのスレッドに表示されます。各スレッドには独自のプライベート スタックがあります。ただし、スタック内のデータは、コードなどで明示的に共有できます。ただし、ご想像のとおり、そのような場合は使用しないでくださいPostThreadMessage

于 2010-02-11T02:16:41.810 に答える
0

他の人がすでに言ったように、どのように記述したかは問題ありません。一般に、スタック上のオブジェクトへのポインターを別のスレッドに渡すときに、すべてが同期されている限り、すぐに失敗することはありません。ただし、例外が発生した場合、またはスレッドの 1 つが非同期 IO コールバックに関与している場合、スレッドセーフに見えるものが意図した順序から外れることがあるため、そうするときに少しうんざりする傾向があります。SendMessage の呼び出し中に他のスレッドで例外が発生した場合、すぐに 0 が返されることがあります。例外が後で別のスレッドで処理される場合は、アクセス違反が発生している可能性があります。さらに別の潜在的な危険は、スタックに格納されているものはすべて、別のスレッドから強制的に破棄できないことです。何らかのコールバック、オブジェクトなどを待ってスタックした場合、

私の要点は次のとおりです。すべてが完全に機能し、何も変更されず、外部の依存関係が失敗しないという単純なシナリオでは、ローカルスタックへのポインターを共有することは安全ですが、ヒープへの割り当ては実際には単純であるため、酌量すべき状況で任意のスレッドからオブジェクトの有効期間を明示的に制御する機会を与えてくれます。なぜヒープを使用しないのでしょうか?

最後に、MyData 構造体の void* chunk_ メンバーには細心の注意を払うことを強くお勧めします。これは、他のスレッドにコピーされた場合、前述のようにスレッドセーフではないためです。

于 2011-09-15T09:14:33.337 に答える
0

あなたが聞いたのは、あるスレッドのプライベート スタック上のデータを別のスレッドと共有する「プライバシーの侵害の可能性」です。

推奨されるものではありませんが、これは「潜在的な」問題にすぎません。正しく同期すれば、安全に実行できます。あなたの場合、この同期は ::SendMessage(); によって行われます。メッセージが他のスレッドで処理されるまで返されないため、データはメイン スレッドのスタックの範囲外にはなりません。ただし、ワーカー スレッドでこのポインターを使用する場合は、メッセージ ハンドラーから戻る前に実行する必要があることに注意してください (ポインターをどこかに保存する場合は、必ずコピーを作成してください)。

于 2010-07-02T08:19:05.080 に答える