5

連続して作成されたスレッドの実行順序に問題があります。これがコードです。

#include <iostream>
#include <Windows.h>
#include <boost/thread.hpp>

using namespace std;

boost::mutex mutexA;
boost::mutex mutexB;
boost::mutex mutexC;
boost::mutex mutexD;


void SomeWork(char letter, int index)
{
    boost::mutex::scoped_lock lock;
    switch(letter)
    {
    case 'A' : lock = boost::mutex::scoped_lock(mutexA); break;
    case 'B' : lock = boost::mutex::scoped_lock(mutexB); break;
    case 'C' : lock = boost::mutex::scoped_lock(mutexC); break;
    case 'D' : lock = boost::mutex::scoped_lock(mutexD); break;
    }

    cout << letter <<index << " started" << endl;
    Sleep(800);
    cout << letter<<index << " finished" << endl; 
}

int main(int argc , char * argv[])
{
    for(int i = 0; i < 16; i++)
    {
        char x = rand() % 4 + 65;
        boost::thread tha = boost::thread(SomeWork,x,i);
        Sleep(10);
    }
Sleep(6000);
    system("PAUSE");
  return 0;
}

文字 (A から D) と生成 ID (i) がメソッド SomeWork にスレッドとして渡されるたびに。文字間の実行順序は気にしませんが、特定の文字、たとえば A の場合、x < y の場合、Ax は Ay の前に開始する必要があります。コードのランダム出力のランダム部分は次のとおりです。

B0開始  
D1開始  
C2開始  
A3開始  
B0終了  
B12開始  
D1終了  
D15開始  
C2終了  
C6始めました  
A3終了  
A9開始
B12完成
B11 開始 --> B12 終了後に B11 開始。
D15終了
D13開始
C6完成
C7始めました
A9終了

どうすればそのような状態を避けることができますか?
ありがとう。


条件変数を使用して問題を解決しました。しかし、私は問題を少し変えました。解決策は、for ループのインデックスを追跡することです。そのため、各スレッドはいつ機能しないかを知っています。しかし、このコードに関する限り、他に 2 点お聞きしたいことがあります。
まず、私のコンピューターで for-loop インデックスを 350 に設定すると、アクセス違反が発生しました。310 はループの数で、問題ありませんでした。そのため、生成されるスレッドの最大数があることに気付きました。どうすればこの数を決定できますか? 次に、Visual Studio 2008 で、コードのリリース バージョンが非常に奇妙な動作を示しました。条件変数を使用せずに (1 行目から 3 行目がコメントアウトされています)、スレッドは順序付けされました。どのようにそれが起こることができますか?

コードは次のとおりです。

#include <iostream>
#include <Windows.h>
#include <boost/thread.hpp>

using namespace std;

boost::mutex mutexA;
boost::mutex mutexB;
boost::mutex mutexC;
boost::mutex mutexD;


class cl
{
public:
    boost::condition_variable con;
    boost::mutex mutex_cl;
    char Letter;
    int num;
    cl(char letter) : Letter(letter) , num(0)
    {

    }
    void doWork( int index, int tracknum)
    {
        boost::unique_lock<boost::mutex> lock(mutex_cl);
        while(num != tracknum)     // line 1
            con.wait(lock);   // line 2 
        Sleep(10);
        num = index;
        cout << Letter<<index << endl; 
        con.notify_all();  // line 3
    }
};

int main(int argc , char * argv[])
{
    cl A('A');
    cl B('B');
    cl C('C');
    cl D('D');

    for(int i = 0; i < 100; i++)
    {   
        boost::thread(&cl::doWork,&A,i+1,i);
        boost::thread(&cl::doWork,&B,i+1,i);
        boost::thread(&cl::doWork,&C,i+1,i);
        boost::thread(&cl::doWork,&D,i+1,i);
    }
    cout << "************************************************************************" << endl;

    Sleep(6000);
    system("PAUSE");
  return 0;
}
4

3 に答える 3

6

ロックを待機している 2 つの異なるスレッドがある場合、前の所有者によってロックが解放されると、どちらがロックを取得するかは完全に非決定論的です。これがあなたが経験していることだと思います。がロックを保持していると想定B10し、その間に と のスレッドが生成されB11ますB12。 どのスレッドが最初に作成されたか、またはどのスレッドが最初に待機を開始したかに関係なく、次にロックを取得するかどうかはB10コイントスにかかっています。B11B12

おそらく、それぞれが作業単位を消費する正確に 4 つのスレッドを生成するように、文字ごとに作業キューを実装する必要がありますか? これは、この方法で順序を簡単に保証する唯一の方法です。複数のスレッドがロックを待機している場合、単純なミューテックスでは順序付けが保証されません。

于 2010-09-03T12:05:23.447 に答える
2

B11 は B12 の前に開始されますが、B12 の前に SomeWork() を実行するための CPU タイム スライスが与えられるとは限りません。この決定は、OS とそのスケジューラー次第です。

Mutex は通常、スレッド間でデータへのアクセスを同期するために使用されますが、スレッド実行のシーケンス (つまり、データ アクセス) に関して懸念が生じています。

グループ「A」のスレッドが同じデータに対して同じコードを実行している場合は、1 つのスレッドのみを使用します。これにより、グループ内のスレッド間のコンテキストの切り替えがなくなり、同じ結果が得られます。データが変化している場合は、生産者/消費者のパターンを検討してください。Paul Bridger は、ここで生産者/消費者のわかりやすい例を示しています

于 2010-09-03T12:34:45.800 に答える
1

スレッドには、実行を開始する前に満たさなければならない依存関係があります。あなたの例では、B12 は B0 と B11 に依存しています。どういうわけか、その依存関係の知識を追跡する必要があります。未完成の依存関係を持つスレッドは待機させる必要があります。

条件変数を調べます。スレッドが SomeWork() を終了するたびに、条件変数の notify_all() メソッドを使用します。次に、待機中のすべてのスレッドは、まだ依存関係があるかどうかを確認する必要があります。その場合は、戻って待ってください。それ以外の場合は、先に進み、SomeWork() を呼び出します。

各スレッドが未完成の依存関係を持っているかどうかを判断するには、何らかの方法が必要です。これはおそらく、グローバルに利用可能なエンティティになります。ミューテックスがある場合にのみ変更する必要があります (SomeWork() 内)。複数のスレッドによる読み取りは、単純なデータ構造では安全です。

于 2010-09-03T13:42:30.380 に答える