-1

我根据 C++11 注释编写了一个非常简单的 Producer/Consumer,无法弄清楚为什么 unique_lock() 在超出范围时不释放锁。

struct Message{
Message(int x):data(x){cout<<"+";}
int data;
};


queue<Message*> g_queue;
condition_variable cv;
mutex m;

void consumer()
{
    do {
        unique_lock<mutex> lck {m};
        cv.wait(lck, [&](){return !g_queue.empty();});
        cout<<"Notified...";
        auto& obj = g_queue.front();
        std::cout<<obj->data;
        g_queue.pop();
        cout<<".";
        lck.unlock(); -----(1)
    } while(1);

}

void producer() 
{
    while(true){
            unique_lock<mutex> lck {m};
            Message msg{5};
            cout<<"Queue size:"<<g_queue.size()<<'\n';
            g_queue.push(&msg);
            cv.notify_one();
            lck.unlock(); -------(2)
            cout<<"-"<<'\n';
            this_thread::sleep_for(std::chrono::milliseconds{2000});
    }
}

并将其用作:-

    thread Q(&consumer);
    thread P(&producer);
    P.join();
    Q.join();

输出是: -

+Queue size:0
-Notified...
5.+Queue size:0
-Notified...5
.+Queue size:0
-Notified...5

所以从技术上讲,是的,生产者需要告诉消费者我准备好了,消费者需要让生产者知道发送更多数据。我不清楚要使用什么,条件变量是这样做还是 unique_lock 是这样做的。

确切地说,当范围可以释放锁时,为什么我需要(1)和(2)

==编辑== 以下是编辑后的代码,效果很好,

void consumer()
{
    do {
        unique_lock<mutex> lck {m};
        cv.wait(lck, [&](){return !g_queue.empty();});
        cout<<"Notified...";
        auto& obj = g_queue.front();
        std::cout<<obj->data;
        g_queue.pop();
        cout<<".";
    } while(1);

}

Message msg{5};
void producer() 
{
    while(true){
            unique_lock<mutex> lck {m};
            cout<<"Queue size:"<<g_queue.size()<<'\n';
            g_queue.push(&msg);
            cv.notify_one();
            cout<<"-"<<'\n';
    }
}

现在,如果我想在 Producer 或 Consumer 如果 sleep 有风险,我该如何引入一点节流?

4

1 回答 1

0

不确定这里是否还有问题,但一种限制的解决方案是在生产者中设置允许队列增长到的最大大小。当队列达到这个大小时,生产者等待不同的条件变量。当队列下降到某个大小以下时,消费者会发出第二个条件变量的信号。(后者的大小可能比最大值略小,以产生一些滞后。)等待这个新条件变量的谓词是g_queue.size() >= max_size

于 2017-12-21T00:28:18.733 回答