5

Microsoft Visual C++ では、CreateThread() を呼び出して、1 つのvoid *パラメーターで関数を開始することでスレッドを作成できます。私はそのパラメーターとして構造体へのポインターを渡します。他の多くの人も同様にそうしているのを見ます。

私の質問は、構造体にポインターを渡している場合、CreateThread() が呼び出される前に構造体のメンバーが実際にメモリに書き込まれたかどうかをどのように知ることができるかということです。それらがキャッシュされないという保証はありますか?例えば:

struct bigapple { string color; int count; } apple;
apple.count = 1;
apple.color = "red";
hThread = CreateThread( NULL, 0, myfunction, &apple, 0, NULL );

DWORD WINAPI myfunction( void *param )
{
    struct bigapple *myapple = (struct bigapple *)param;

    // how do I know that apple's struct was actually written to memory before CreateThread?
    cout << "Apple count: " << myapple->count << endl; 
}

今日の午後、本を読んでいるときに、この Web サイトやその他の Web サイトで、揮発性ではないデータをスレッドに渡す Windows コードがたくさん見られました。メモリ バリアなどはないようです。C ++または少なくとも古いリビジョンは「スレッド対応」ではないことを知っているので、他の理由があるのではないかと思っています。私の推測では、コンパイラは、CreateThread() への呼び出しでポインター &apple を渡したことを認識しているのでapple、呼び出しの前にのメンバーを書き出すことを認識しています。

ありがとう

4

5 に答える 5

5

いいえ。関連する Win32 スレッド関数はすべて、必要なメモリ バリアを処理します。以前のすべての書き込みはCreateThread、新しいスレッドに表示されます。明らかに、その新しく作成されたスレッドの読み取りは、への呼び出しの前に並べ替えることはできませんCreateThread

volatileコンパイラに特別な有用な制約を追加することはなく、単にコードを遅くするだけです。ただし、実際には、新しいスレッドを作成するコストと比較すると、これは目立ちません。

于 2012-09-11T07:16:06.483 に答える
2

いいえ、そうすべきではありませんvolatile。同時に、有効な問題を指摘しています。キャッシュの詳細な操作については、Intel/ARM/etc の論文で説明されています。

それでも、データがWILL BE WRITTENであると安全に想定できます。そうしないと、あまりにも多くのものが壊れてしまいます。数十年の経験がそうであることを物語っています。

スレッド スケジューラが同じコアでスレッドを開始する場合、キャッシュの状態は問題ありません。そうでない場合、カーネルはキャッシュをフラッシュします。そうしないと、何も機能しません。

volatileスレッド間の相互作用には使用しないでください。これは、スレッド内のみでデータを処理する方法に関する命令です (レジスタ コピーを使用するか、常に再読み取りを行うなど)。

于 2012-09-11T06:36:43.443 に答える
1

まず、オプティマイザは正確さを犠牲にして順序を変更することはできないと思います。CreateThread() は関数であり、関数呼び出しのパラメーターのバインドは、呼び出しが行われる前に行われます。

第二に、揮発性は意図した目的にはあまり役に立ちません。この記事をチェックしてください

于 2012-09-11T05:41:34.127 に答える
0

質問は別の文脈で有効だと思います。他の人が構造体を使用して指摘しているように、内容は安全です(ただし、データへのアクセスは同期する必要があります)。

ただし、スレッドの外部で変更できるアトミック変数(またはそのポインター)がある場合、この質問は有効だと思います。その場合の私の意見は、この場合は揮発性を使用する必要があるということです。

編集: ウィキページの例は良い説明だと思いますhttp://en.wikipedia.org/wiki/Volatile_variable

于 2012-09-11T07:37:02.213 に答える
0

あなたは問題がないことに苦労しており、少なくとも他の2つを作成しています...

  1. CreateThread に指定されたパラメーターについて心配する必要はありません。スレッドの作成時に存在する場合は、CreateThread が戻るまで存在します。また、それらを作成したスレッドはそれらを破棄しないため、他のスレッドでも使用できます。
  2. 問題は、いつ、誰が破棄されるかということです: を使用して作成するとnew、 adeleteが呼び出されるまで (またはプロセスが終了するまで: メモリ リークが発生します!) 、存在します。
  3. プロセスは、そのメイン スレッドが終了すると終了します (そして、他のすべてのスレッドも OS によって終了されます!)。そして、メインには、他のスレッドが完了するのを待つようにするものは何もありません。
  4. CreateThread独自のライブラリもスレッドとインターフェースするフォーム言語のような低レベル API を使用する場合は注意してください。C ランタイムには_beginthreadex. C++ ライブラリの他の初期化タスクも呼び出しCreateThreadて実行します。一部の C (および C++) ライブラリ関数は、これらの初期化がないと正しく動作しない場合があります。これは、終了時にランタイム リソースを適切に解放するためにも必要です。Unsingは、クリーンアップに使用されるコンテキストで使用するCreateThreadようなものです。mallocdelete

適切なメイン スレッドの動作は、

// create the data
// create the other thread
// // perform othe task
// wait for the oter thread to terminate
// destroy the data

win32 API ドキュメントで明確に述べられていないことは、everyHANDLEwaitableであり、関連付けられたリソースが解放されると通知されるということです。他のスレッドの終了を待つには、メインスレッドを呼び出すだけです

WaitForSingleObject(hthread,INFINITE);

したがって、メインスレッドはより適切になります。

{
    data* pdata = new data;
    HANDLE hthread = (HANDLE)_beginthreadex(0,0,yourprocedure, pdata,0,0);
    WaitForSingleObject(htread,INFINITE);
    delete pdata;
}

あるいは

{
    data d;
    HANDLE hthread = (HANDLE)_beginthreadex(0,0,yourprocedure, &d,0,0);
    WaitForSingleObject(htread,INFINITE);
}
于 2012-09-11T06:50:23.277 に答える