8

私は現在、拡張された Producer-Worker モデルをシミュレートする問題に取り組んでいます。この問題では、3 人のワーカーと 3 つのツールが利用可能であり、ワーカーが作業するには 2 つのツールが必要です (および材料ですが、それらは無関係です)。ボールトに 2 つ以上のツールがある場合、ワーカーは 2 つ取得します。

これは 2 人のワーカーで問題ありません。1 人は作業してからツールを保管庫に戻し、もう 1 人の待機中のワーカーは目覚めて 2 つのツールを受け取ります。問題は、作業員が 3 人いると、常に 1 人が道具を手に入れるのに飢えていることです。

いくつかのテストの後、条件変数を待っているスレッドがスタック形式で構造化されていることに気付きました。とにかくそれをキュー形式にすることは可能ですか? (1は待って、2は待って、3は待って。1が目覚めて別のを作りたいときは、2と3の後ろで待たなければならない。)

出力例を次に示します。コードが長すぎるので、本当に必要な場合は投稿します。3 つのワーカー スレッドと 1 つのツール ミューテックスがあります。誰が飢えているかは、実行ごとに異なります。

1 Tools taken. Remaining: 1
2 Waiting on tools...
3 Waiting on tools...
1 Operator Product made. Tools returned. Tools now:3
3 Tools taken. Remaining: 1
1 Waiting on tools...
3 Materials returned for switch.
3 Operator Product made. Tools returned. Tools now:3
1 Tools taken. Remaining: 1
3 Waiting on tools...
1 Materials returned for switch.
1 Operator Product made. Tools returned. Tools now:3
3 Tools taken. Remaining: 1
1 Waiting on tools...
3 Materials returned for switch.
3 Operator Product made. Tools returned. Tools now:3
1 Tools taken. Remaining: 1
3 Waiting on tools...
1 Materials returned for switch.
1 Operator Product made. Tools returned. Tools now:3
3 Tools taken. Remaining: 1
1 Waiting on tools...
3 Materials returned for switch.
3 Operator Product made. Tools returned. Tools now:3
1 Tools taken. Remaining: 1
3 Waiting on tools...
1 Materials returned for switch.
...

(ご覧のとおり、2はツールを取得しません...)

更新: 2013/07/05 コードを追加しました。

int tools = 3; //global
string last; //current last product on output buffer
mutex toolsMutex;
mutex matSearchMutex;

int main(){
//Initializing Producers
    Producer prod1(1);
    Producer prod2(2);
        Producer prod3(3);



    thread p1(processor,1);
    thread p2(processor,2);
    thread p3(processor,3);

    p1.detach();
    p2.detach();
    p3.detach();

    while(true){//forever running

    }

    return 0;
}

プロセッサー:

  //Processor method
void processor(int i){
    srand(time(NULL)); 

    while (true){ //forever running


    bool hasTools = false;
    bool productMade = false;
    while (productMade == false){ //while product has yet to be made.
        //choose what to make...



        if (hasTools == false){
            thread matT(getMaterials,whatToMake);
            thread toolT(getTools,i);
            toolT.join();           
            matT.join();
            hasTools = true;
        }
        else{ //tools acquired but no materials
            thread matT(getMaterials,whatToMake);
            matT.join();
        }

        if (recordedLast.compare(last) != 0){

            //return materials and acquire new ones the next run

            continue;
        }
        else {
            makeProduct(whatToMake);
            unique_lock<mutex> locker(toolMutex); 
            tools = tools + 2;
            cout << i << " Operator Product made. Tools returned. Tools now:" << tools << endl;
            productMade = true;
            if (tools >=2)  toolsCV.notify_one();
        }

    //done processing

    }


}   

}

作る製品:

void makeProduct(int i){
    unique_lock<mutex> mainMatLock(matSearchMutex); 
    // make product according to i
    this_thread::sleep_for(chrono::milliseconds(rand() % 1000 + 10));   
}

getTools:

void getTools(int i){
    unique_lock<mutex> locker(toolMutex); 
    if (tools <2){
        cout << i << " Waiting on tools..." << endl;
        toolsCV.wait(locker);}
    tools = tools - 2;//tools acquired
    cout << i <<" Tools taken. Remaining: " << tools << endl;

}

返信してくれた人に感謝します。今夜は、複数の条件変数を使用して待機キューを実装してみます。

(PS ここ Stack Overflow でコードの書式設定を行うためのより良い方法はありますか? 4 つのスペース以外...

4

4 に答える 4

13

std::condition_variableを呼び出したときにどの待機中のスレッドが起動されるかを指定しませんnotify_one。したがって、どのスレッドが起動されるかを気にしないコードを作成する必要があります。標準的なパターンでは、どのスレッドが起動されても、そのスレッドは実行する必要がある作業を実行する必要があります。

スレッドを特定の順序で起動する必要がある場合は、別のメカニズムを使用してください。たとえば、std::condition_variableスレッドごとに個別に設定し、ツールが必要なときにスレッドをキューに入れることができます。スレッドがツールを渡すと、キューの先頭にあるスレッドに対応する条件変数にシグナルを送ることができます。その後、そのスレッドが起動され、他のスレッドはスリープ状態のままになります (モジュロ スプリアス ウェイクアップ)。

于 2013-07-02T10:17:44.280 に答える
3

条件で待機しているスレッドが複数ある場合、それらが起動される順序 ( notify_all) またはどのスレッドが起動されるか ( notify_one) は指定されていません。何らかの順序付けが必要な場合は、 を使用notify_allして自分で実装する必要があります。スレッドのキューを待機させておくことができます。待機する前に (ただしミューテックスを取得した後)、スレッド ID をキューの最後にプッシュします。ループでは、「このスレッドはキューの前にあり、必要なツールが利用可能です」をループします。ツールを取得したら、キューの先頭から ID を削除し、 notify_all再度呼び出します。

于 2013-07-02T08:28:53.560 に答える
1

ここでの本当の問題は、ワーカー スレッドがあり、必要なリソースの量が限られている場合、どのスレッドが実際にアクティブ化されているかを気にする必要はなく、作業が完了することだけを気にする必要があるということです。ここでの唯一の違いは、ロギングにあります。定義したスレッドの数は、並行して実行できるスレッドの数であり、リソースによって 1 つに制限されます。

これがうまくいかない場合は、他の回答で説明されているように、自分で行動を起こす必要があります。

于 2013-07-02T10:01:26.940 に答える