4

私はスレッド化を学んでおり、いくつかの簡単な例を見つけました。

私が望んでいるのは、5 つのスレッドを作成することです。各スレッドは、20 個の int の配列に乱数を割り当てます。最後に、この配列をより大きな 100 サイズの int に再構築する別の 5 つのスレッドを用意します。

ここに私が試していたいくつかの以前のコードがあります。運が悪くても、参照によって配列を渡すことができることを望んでいました。

どんなアイデアでも大歓迎です、覚えておいてください、私はスレッドにまったく慣れていません

#include <process.h>
#include <windows.h>
#include <iostream>
#include <fstream>
#include <time.h>
//#include <thread>

using namespace std;

void myThread (void *dummy );
void myThread2 (void *dummy );

int main()
{

    ofstream myfile;
    myfile.open ("coinToss.csv");

    int rNum;

    long numRuns;
    long count = 0;
    int divisor = 1;
    float holder = 0;
    int counter = 0;
    float percent = 0.0;

    int array1[1000000];
    int array2[1000000];


    srand ( time(NULL) );

    printf ("Runs (use multiple of 10)? ");
    cin >> numRuns;

    for (int i = 0; i < numRuns; i++)
    {
        _beginthread( myThread, 0, (void *) (array1) );
        _beginthread( myThread2, 0, (void *) (array2) );

    }

}

void myThread (void *param )
{
    int i = *(int *)param;

    for (int x = 0; x < 1000000; x++)
    {
        //param[x] = rand() % 2 + 1;
        i[x] = rand() % 2 + 1;
    }

}

void myThread2 (void *param )
{
    int i[1000000] = *(int *)param;

    for (int = 0; x < 1000000; x++)
    {
        i[x] = rand() % 2 + 1;
    }

}
4

3 に答える 3

5

あなたが認識する必要がある最初のこと:

 for (int i = 0; i < numRuns; i++)
    {
        _beginthread( myThread, 0, (void *) (array1) );
        _beginthread( myThread2, 0, (void *) (array2) );

    }

コールはすぐ_beginthreadに戻ります。スレッドが終了するのも、開始するのも待ちません。OSのスケジューラでスレッドをキューに入れ、戻るだけです。

ただし、上記のコードは関数の終わりですmain()。リリース ビルドでは、プログラム全体が終了する前にスレッドが初期化されるとは思えません。プログラムがシャットダウンする前に、ワーカー スレッドが作業を終了するのをメイン スレッドが待機するメカニズムを構築する必要があります。これを行うことは SO 投稿の範囲をはるかに超えていますが、CreateEvent()WaitForMultipleObjects( ) を調べてください。

次に理解する必要があるのは、スレッドに送信するものの有効期間と所有権のセマンティクスです。スコープ内の自動変数である配列へのポインターを渡していますmain()

 int array1[1000000];
 int array2[1000000];

これらの配列が宣言されているスコープ (ここではmain()) が終了するとすぐに、変数は存在しなくなります。ローカル スコープの変数へのポインターをワーカー スレッドに渡すことは、ほとんどの場合正しくありません。スレッドが終了する前にローカル スコープが終了する場合は、決して正しくありません。

これらの配列を動的に割り当ててから、それらの所有権をワーカー スレッドに移すと、ここでその問題が解決されます。これを行う場合、これらのオブジェクト/配列の所有権のセマンティクスを管理する際には注意してください。

于 2012-10-09T14:16:20.847 に答える
3

1.キャスティング:

キャスティングに注目!

void myThread (void *param )
{
  int *i = (int *) param;
  for (int x = 0; x < 1000000; x++)
  {
    i[x] = rand() % 2 + 1;
  }
}

2. 範囲:

両方のスレッドが開始numRuns時刻です。それらを開始するには、しばらく時間がかかります。それらも実行します。mainスレッドを考慮せずに を終了しないでください。 WaitForMultipleObjects を使用してスレッドを監視する必要があります。_beginthread() は を返しますwaitable handle

実装:

int main()
{
  long numRuns;
  HANDLE hThread[MAX_WAIT_OBJECTS];

  cin >> numRuns;
  // numRuns to be smaller than MAX_WAIT_OBJECTS/2!!!!


  for (int i = 0; i < numRuns; i++)
  {
     hThread[i * 2]     = _beginthread( myThread, 0, (void *) (array1) );
     hThread[i * 2 + 1] = _beginthread( myThread2, 0, (void *) (array2) );
     // or better use _beginthreadex(...)
  }
  WaitForMultipleObjects(numRuns * 2, hThread, TRUE, INFINITE);
  // bWaitAll flag set TRUE causes this statement to wait until all threads have finished.
  // dwMilliseconds set to INFINITE will force the wait to not timeout.
}

この方法ではmain、すべてのスレッドがジョブを完了したときにのみ終了します。

3. アクセス:

両方の配列がmainセクションで宣言されているため、スレッドはそれらを共有しています。アクセスを保護するために、何らかの排他性を導入する必要があります。最も簡単なのはCritical Section Objectです。すべてのスレッド 2 が array2 のみにアクセスし、すべてのスレッド 1 が array1 のみにアクセスしている場合、2 つのクリティカル セクション オブジェクトを使用することをお勧めします。クリティカル セクションには、一度に 1 つのスレッドしかアクセスできません。

実装:

CRITICAL_SECTION cs1,cs2; // global

int main()
{
  long numRuns;
  HANDLE hThread[1000];

  // critical section object need to be initialized before aquired
  InitializeCriticalSection(&cs1);
  InitializeCriticalSection(&cs2);

  cin >> numRuns;

  for (int i = 0; i < numRuns; i++)
  {
    hThread[i * 2]     = _beginthread( myThread, 0, (void *) (array1) );
    hThread[i * 2 + 1] = _beginthread( myThread2, 0, (void *) (array2) );
  }
  WaitForMultipleObjects(numRuns * 2, hThread, TRUE, INFINITE);
}

スレッド (ここでは 1 つだけを示します):

void myThread1 (void *param )
{
  EnterCriticalSection(&cs1); //aquire the critical section object
  int *i = (int *) param;
  for (int x = 0; x < 1000000; x++)
  {
    i[x] = rand() % 2 + 1;
  }
  LeaveCriticalSection(&cs1); // release the critical section object
}

ただし、全体の話はまだ少し不明です。多数のスレッドが同じ配列を最初から最後まで同時に埋める必要があります。それは奇妙に聞こえます。ここで説明したクリティカル セクション オブジェクトを使用すると、いずれにせよ、スレッドは次々に実行されます。一体何を目指しているのでしょうか?

于 2012-10-09T15:02:45.570 に答える
1

他の回答は主なポイントをカバーしています:しばしば問題になる別の回答があります(少なくともLINUXでは:Windowsについてはわかりません)

int array1[1000000];
int array2[1000000];

非常に大きな配列をローカル変数として宣言すると、スタック スペースがオーバーフローしてプログラムがクラッシュする危険があります。

于 2012-10-10T07:18:25.320 に答える