簡體   English   中英

std :: conditional_variable :: notify_all不會喚醒所有線程

[英]std::conditional_variable::notify_all does not wake up all the threads

我這里有一個簡單的例子:

由於我嘗試學習c ++ 11線程,因此該項目可以稱為學術項目。 這是正在發生的事情的描述。

想象一下一個很大的std::string ,里面有很多匯編源代碼,例如

mov ebx,ecx; \\ r \\ nmov eax,ecx; \\ r \\ n ....

Parse()函數采用此字符串並通過標記行的開始和結束並將其另存為工作隊列中的string::const_iterators來查找所有行位置。

之后,有2個工作線程從隊列中彈出此信息,並將子字符串解析為Intstuction類對象。 他們將指令類的結果實例推回std::vector<Instruction> result

這是一個結構聲明,用於保存行號和要解析的子字符串的迭代器

struct JobItem {
    int lineNumber;
    string::const_iterator itStart;
    string::const_iterator itEnd;
};

那是一個小的記錄器...

void ThreadLog(const char* log) {
    writeMutex.lock();
    cout << "Thr:" << this_thread::get_id() << " " << log << endl;
    writeMutex.unlock();
}

那就是共享數據:

queue<JobItem> que;
vector<Instruction> result;

這是所有要同步的原語

condition_variable condVar;
mutex condMutex;
bool signaled = false;

mutex writeMutex;
bool done=false;
mutex resultMutex;
mutex queMutex;

每線程功能

void Func() {
    unique_lock<mutex> condLock(condMutex);
    ThreadLog("Waiting...");
    while (!signaled) {
        condVar.wait(condLock);
    }
    ThreadLog("Started");
    while (!done) {
        JobItem item;
        queMutex.lock();
        if (!que.empty()) {
            item = que.front(); que.pop();
            queMutex.unlock();
        }
        else {
            queMutex.unlock();
            break;
        }
        //if i comment the line below both threads wake up
        auto instr = ParseInstruction(item.itStart, item.itEnd);
        resultMutex.lock();
        result.push_back(Instruction());
        resultMutex.unlock();
    }

管理線程的管理器功能...

vector<Instruction> Parser::Parse(const string& instructionStream){
    thread thread1(Func);
    thread thread2(Func);

    auto it0 = instructionStream.cbegin();
    auto it1 = it0;
    int currentIndex = instructionStream.find("\r\n");
    int oldIndex = 0;
    this_thread::sleep_for(chrono::milliseconds(1000)); //experimental 


    int x = 0;
    while (currentIndex != string::npos){
        auto it0  = instructionStream.cbegin() + oldIndex;
        auto it1  = instructionStream.cbegin() + currentIndex;

        queMutex.lock();
        que.push({ x,it0,it1 });
        queMutex.unlock();
        if (x == 20) {//fill the buffer a little bit before signal
            signaled = true;
            condVar.notify_all();
        }
        oldIndex = currentIndex + 2;
        currentIndex = instructionStream.find("\r\n", oldIndex);
        ++x;
    }
    thread1.join();
    thread2.join();
    done = true;

    return result;
}

問題出現在Func()函數中。 如您所見,我正在其中使用一些日志記錄。 日志說:

Output:
Thr:9928 Waiting...
Thr:8532 Waiting...
Thr:8532 Started

這意味着在主線程已將notify_all()發送給等待的線程之后,實際上只有其中一個醒來。 如果我注釋掉Func() ParseInstruction()內部對ParseInstruction()的調用,則兩個線程都將喚醒,否則只有一個線程正在喚醒。 得到一些建議將是很棒的。

假設Func讀取signaled並看到它為假。

然后Parsesignaled真實,是否notify_all ; 此時Func不在等待中,因此看不到通知。

然后, Func等待條件變量並阻塞。

您可以通過將一綹避免這種condMutex分配給左右signaled

這是正確使用條件變量的正常模式-您需要測試和修改要在同一互斥鎖中等待的條件。

暫無
暫無

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

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