簡體   English   中英

boost :: threads執行順序

[英]boost::threads execution ordering

我對連續創建的線程的執行順序有疑問。 這是代碼。

#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)和一個genereaion id(i)傳遞給方法SomeWork作為一個線程。 我不關心字母之間的執行順序,但對於一個特殊的字母,比如A,Ax必須在Ay之前開始,如果x <y。 隨機輸出代碼的隨機部分是:

B0 started  
D1 started  
C2 started  
A3 started  
B0 finished  
B12 started  
D1 finished  
D15 started  
C2 finished  
C6 started  
A3 finished  
A9 started
B12 finished
B11 started --> B11 started after B12 finished.
D15 finished
D13 started
C6 finished
C7 started
A9 finished

怎么能避免這種情況?
謝謝。


我使用條件變量解決了問題。 但我改變了一點問題。 解決方案是跟蹤for循環的索引。 所以每個線程都知道什么時候不起作用。 但就這段代碼而言,還有兩件我想問的問題。
首先,在我的計算機上,當我將for循環索引設置為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;
}

如果你有兩個不同的線程在等待鎖定,那么一旦前一個持有者釋放鎖定,它將完全不確定。 我相信這正是你所經歷的。 假設B10持有鎖,並且同時為B11B12產生線程。 B10釋放鎖定 - 關於B11B12接下來是否獲得它,無論首先創建哪個線程,或者甚至哪個線程開始等待,它都是硬幣投擲。

也許你應該為每個字母實現工作隊列,這樣你就會產生4個線程,每個線程都消耗工作單元? 這是以這種方式輕松保證訂購的唯一方法。 如果多個線程正在等待鎖定,則簡單的互斥鎖不會保證排序。

即使B11在B12之前啟動,也不能保證在B12之前執行一些CPU時間片來執行SomeWork()。 此決定取決於操作系統及其調度程序。

Mutex通常用於同步線程之間的數據訪問,並且已經引起了線程執行序列(即數據訪問)的問題。

如果組'A'的線程在相同數據上執行相同的代碼,則只使用一個線程。 這將消除組中線程之間的上下文切換並產生相同的結果。 如果數據正在改變,則考慮生產者/消費者模式。 Paul Bridger 在這里給出了一個易於理解的生產者/消費者示例。

您的線程具有在開始執行之前必須滿足的依賴項。 在您的示例中,B12取決於B0和B11。 不知何故,你必須追蹤這種依賴性知識。 必須使具有未完成依賴項的線程等待。

我會研究條件變量 每次線程完成SomeWork()時,它都會使用條件變量的notify_all()方法。 然后,所有等待的線程必須檢查它們是否仍然具有依賴性。 如果是這樣,請回去等待。 否則,請繼續調用SomeWork()。

您需要某種方式為每個線程確定它是否具有未完成的依賴項。 這可能是一些全球可用的實體。 您應該只在擁有互斥鎖時修改它(在SomeWork()中)。 對於簡單的數據結構,多線程讀取應該是安全的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM