簡體   English   中英

跨多個線程的unique_lock

[英]unique_lock across various threads

我有一個消費者和兩個生產者。 當我同時產生兩個生產者時,它們似乎互相鎖定,因為我們看到的第一個值分別是223和889。

有人可以解釋一下這里發生了什么嗎?

#include<vector>
#include<thread>
#include<iostream>
#include<mutex>
#include<chrono>
#include <condition_variable>

using namespace std;

vector<double>testvec;
mutex mtx;
condition_variable cv;

class Base
{
public:
    Base() {};
    void dosomething();
    int i;
};

void Base::dosomething()
{
    while(1)
    {
        std::unique_lock<std::mutex> ulck(mtx);
        testvec.push_back(i);
        ulck.unlock();
        cv.notify_all();
        i++;
        std::this_thread::sleep_for (std::chrono::milliseconds(i));
    }
};

class Derived1 : public Base
{
public:
    Derived1() {i = 222;}
};

class Derived2 : public Base
{
public:
    Derived2() {i = 888;}
};

class Consumer
{
public:
    Consumer() {}
    void dostuff();
};

void Consumer::dostuff()
{
    while(1)
    {
        std::unique_lock<std::mutex> ulck(mtx);    //locks shared data
        cv.wait(ulck);
        cout<<"last value: "<<testvec.back()<<endl;
        ulck.unlock();
    }
}

int main( int argc, char ** argv )
{
    Derived1 derived1;
    Derived2 derived2;
    Consumer c;

    std::thread t1(&Derived1::dosomething, &derived1);
    std::thread t2(&Derived2::dosomething, &derived2);
    std::thread t3(&Consumer::dostuff, &c);

    t1.join();
    t2.join();
    t3.join();
}

output is:
last value: 223
last value: 224
last value: 225
last value: 889
last value: 226
last value: 227
last value: 228
last value: 229
last value: 890
last value: 230

expected output:
last value: 888 (or 222)
last value: 222 (or 888)
last value: 223
...

沒有謂詞,您永遠不會從wait獲得理智的行為。 另外,為什么只繼續釋放鎖以立即再次鎖定?

這是您要做的事情:

void Consumer::dostuff()
{
    std::unique_lock<std::mutex> ulck(mtx);    //locks shared data
    int i = 0;
    while(1)
    {

        // Correctly decide when to wait and when to stop waiting
        while (testvec.empty() || (testvec.back() == i))
            cv.wait(ulck);

        i = testvec.back();
        cout<<"last value: "<<testvec.back()<<endl;
    }
}

條件變量是無狀態的,沒有辦法知道它們應該等待還是何時停止等待,因為它們是共享狀態的函數。 使用互斥鎖保護共享狀態是您的責任。

請注意,此代碼僅在必須wait時才調用wait。 您只能通過檢查共享狀態來判斷是否需要等待。 並注意它在必須wait同時繼續調用wait。 同樣,您只能通過檢查共享狀態來判斷是否可以停止等待。 共享狀態是您的責任-條件變量是無狀態的。

我有一個消費者和兩個生產者。

錯誤。 您有2個生產者和一個采樣器。 什么都沒有消耗。

您可能想要的是(簡化后):

#include<deque>
#include<thread>
#include<iostream>
#include<mutex>
#include<chrono>
#include <condition_variable>

using namespace std;

deque<double> testvec;
mutex mtx;
condition_variable cv;

auto producer = [](int i)
{
    while(1)
    {
        std::unique_lock<std::mutex> ulck(mtx);
        testvec.push_back(i);
        ulck.unlock();
        cv.notify_all();
        i++;
        std::this_thread::sleep_for (std::chrono::milliseconds(i));
    }
};

void consume()
{
    while(1)
    {
        std::unique_lock<std::mutex> ulck(mtx);    //locks shared data


        // wait until there is something to consume...
        cv.wait(ulck, [&]{return not testvec.empty(); });

        /// ... consume it...
        auto val = testvec.front();
        testvec.pop_front();

        /// ... now unlock and work with the consumed data while unlocked
        ulck.unlock();

        /// ... do work
        cout<<"last value: " << val <<endl;
    }
}

int main( int argc, char ** argv )
{
    std::thread t1(producer, 222);
    std::thread t2(producer, 888);
    std::thread t3(consume);

    t1.join();
    t2.join();
    t3.join();
}

示例輸出:

last value: 222
last value: 888
last value: 223
last value: 224
last value: 225
last value: 889
last value: 226
...

暫無
暫無

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

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