4

私はマルチスレッドに少し慣れていないので、これらの質問が簡単すぎる場合はご容赦ください。

私のアプリケーションは、スレッド内に複数のスレッドを作成し、各スレッドからアクションを実行する必要があります。

たとえば、読み取るファイルのセット、たとえば50があり、CreateThread()関数を使用してこれらのファイルを読み取るスレッドを作成します。

これで、このメインスレッドはファイルにアクセスするための4つのスレッドを作成します。最初のスレッドにはファイル1、2番目のファイル2というように与えられます。

1番目のスレッドがファイル1の読み取りを完了し、メインスレッドに必要なデータを提供した後、メインスレッドはファイル5でそれを呼び出し、そこからデータを取得する必要があります。50個のファイルがすべて読み取られるまで、他のすべてのスレッドについても同様です。

その後、各スレッドが破棄され、最後にメインスレッドが破棄されます。

私が直面している問題は次のとおりです。

1)ファイルの読み取り後にスレッドを停止して終了するにはどうすればよいですか?

2)他のファイル名でスレッドを再度呼び出す方法は?

3)子スレッドはどのようにメインスレッドに情報を提供しますか?

4)スレッドがファイルの読み取りを完了し、メインスレッドにデータを返した後、メインスレッドはどのスレッドがデータを提供したかをどのように知るのでしょうか。

ありがとう

4

3 に答える 3

4

これは、マルチスレッド プログラミングで非常に一般的な問題です。これを生産者と消費者の問題として見ることができます: メインスレッドは、ワーカースレッドによって「消費」されるタスクを「生成」します (seg http://www.mario-konrad.ch/blog/programming/multithread/tutorial-06 .html ) . 「スレッドプール」についても読みたいと思うかもしれません。

ブーストの同期 ( http://www.boost.org/doc/libs/1_50_0/doc/html/thread.html ) を読み、プラットフォームに依存せず使いやすいブーストのスレッド機能を使用することを強くお勧めします。

質問をより具体的にするには:実行する操作を含むキューを作成する必要があります(通常、すべてのワーカースレッドで同じキューです。スレッド1がタスク1、5、9を実行していることを本当に確認したい場合...ワーカー スレッドごとに 1 つのキューが必要です)。このキューへのアクセスは によって同期される必要があり、新しいデータがミューテックスに追加さmutexれると、待機中のスレッドに通知できます。condition_variables

while ([exit condition not true])1.) スレッド関数を終了せず、条件が発生するまで待ってから、ループを使用して再開する

2.) 1 を参照してください。

3.) 両方がアクセスでき、mutex(結果キューなど)によって保護されている任意の変数を介して

4.) この情報を、結果キューに書き込まれた結果として追加します。

もう 1 つのアドバイス: マルチスレッドを正しく処理するのは常に困難です。そのため、デッドロックや競合状態を検出するためのテストを作成し、できるだけ注意してください。

于 2012-07-20T10:00:17.180 に答える
0

この種の問題の一般的な解決策は、スレッド プールとキューを使用することです。メイン スレッドは、すべてのファイル/ファイル名をキューにプッシュしてから、スレッド プール (つまり、各スレッドがキューから項目を取得して処理する別のスレッド) を開始します。1 つの項目が処理されると、次の項目に進みます (それまでにキューがまだ空でない場合)。メイン スレッドは、キューが空ですべてのスレッドが終了すると、すべてが処理されたことを認識します。

したがって、1) と 2) は多少矛盾しています。スレッドを停止して再度呼び出すのではなく、キューでアイテムが見つかる限り実行を続けます。3) については、スレッドが情報を入れ、メインスレッドがそこから読み取るキューを再び使用できます。4) については、各スレッドに ID を与え、それをデータと一緒に置くことができます。ただし、通常、メイン スレッドは、どのスレッドがデータを正確に処理したかを知る必要はありません。

アイデアを提供するための非常に基本的な擬似コードがいくつかあります。スレッドセーフのためのロックは省略されています。

//main
for( all filenames )
  queue.push_back( filename );

//start some thread
threadPool.StartThreads( 4, CreateThread( queue ) );

//wait for threads to end
threadPool.Join();

//thread
class Thread
{
public:
  Thread( queue q ) : q( q ) {}

  void Start();

  bool Join();

  void ThreadFun()
  {
    auto nextQueueItem = q.pop_back();
    if( !nextQueuItem )
      return; //q empty
    ProcessItem( nextQueueItem );
  }
}
于 2012-07-20T10:01:42.740 に答える
0

Synchronies ファイルの読み取りを実行するためにスレッド プールを使用するかどうかに関係なく、シリアル化して実行する必要がある関数のチェーンまたは関数のグループに要約されます。したがって、関数を並列に実行する方法 (関数ごとに 1 つのスレッドを開始するか、スレッド プールを使用するか) を見つけて、最初の 4 つのファイルが読み取られるのを待つ方法を見つけたとします。そこに結果をプッシュすると、5 番目の関数がキューから 4 つの結果をプルし (キューが空になるとブロックします)、処理します。関数間にさらに依存関係がある場合は、関数間にさらにキューを追加できます。スケッチ:

void read_file( const std::string& name, queue& q )
{
    file_content f= .... // read file
    q.push( f )
}

void process4files( queue& q )
{
    std::vector< file_content > result;
    for ( int i = 0; i != 4; ++i )
        result.push_back( q.pop() ); 

    // now 4 files are read ...
    assert( result.size() == 4u );
}

queue       q;
thread t1( &read_file, "file1", q );
thread t2( &read_file, "file2", q );
thread t3( &read_file, "file3", q );
thread t4( &read_file, "file4", q );
thread t5( &process4files, q );

t5.join();

理解していただければ幸いです。

トルステン

于 2012-07-20T11:07:33.730 に答える