在两个线程之间同步队列

时间:2016-09-23 14:17:46

标签: c++ multithreading c++11

这是一个简单的程序,它有一个函数start(),它等待用户输入内容(使用无限循环)并将其存储在队列中。 start()在一个单独的线程中运行。用户输入一些值后,队列的大小在main中保持为零。如何同步队列?
代码:source.cpp

#include <iostream>
#include "kl.h"

using namespace std;

int main()
{
    std::thread t1(start);
    while (1)
    {
        if (q.size() > 0)
        {
            std::cout << "never gets inside this if\n";
            std::string first = q.front();
            q.pop();
        }           
    }
    t1.join();
}

代码:kl.h

#include <queue>
#include <iostream> 
#include <string>

void start();
static std::queue<std::string> q;

代码:kl.cpp

#include "kl.h"
using namespace std;

void start()
{
    char i;
    string str;
    while (1)
    {
        for (i = 0; i <= 1000; i++)
        {
            //other stuff and str input
            q.push(str);
        }

    }
}

2 个答案:

答案 0 :(得分:1)

您的代码包含race - 我崩溃了;两个线程都可能修改共享队列。 (另外,您可以使用char i循环播放高达1000的值 - 可能不是一个好主意。)

您应该使用std::mutex保护共享队列,并使用std::condition_variable通知有理由检查队列。

具体来说,您应该考虑以下事项(这对于a producer consumer的情况很常见):

  1. 仅在持有互斥锁时访问队列。

  2. 使用条件变量通知您已将某些内容推入其中。

  3. 使用条件变量指定何时需要继续处理的条件。

  4. 以下是对代码的重写:

    #include <iostream>
    #include <queue>
    #include <thread>
    #include <condition_variable>
    #include <mutex>
    
    using namespace std;
    
    std::queue<std::string> q;
    std::mutex m;
    std::condition_variable cv;
    
    void start()
    {
        string str;
        for (std::size_t i = 0; i <= 1000; i++) {
            //other stuff and str input
            std::cout << "here" << std::endl;
            std::unique_lock<std::mutex> lk(m);
            q.push(str);
            lk.unlock();
            cv.notify_one();
        }
    }
    
    int main()
    {
        std::thread t1(start);
        for (std::size_t i = 0; i <= 1000; i++)
        {
            std::unique_lock<std::mutex> lk(m);
            cv.wait(lk, []{return !q.empty();});
            std::string first = q.front();
            q.pop();    
        }
        t1.join();
    }
    

答案 1 :(得分:0)

我的同步队列类示例及其用法:

template<typename T>
class SyncQueue
{
    std::queue<T> m_Que;
    std::mutex m_Lock;
    std::condition_variable m_ConVar;

public:
    void enque(T item)
    {
        std::unique_lock<std::mutex> lock(m_Lock);
        m_Que.push(item);
        lock.unlock();
        m_ConVar.notify_all();
    }

    T deque()
    {
        std::unique_lock<std::mutex> lock(m_Lock);

        do
        {
            m_ConVar.wait(lock);

        } while(m_Que.size() == 0); // extra check from spontaneous notifications

        auto ret = m_Que.front();
        m_Que.pop();

        return ret;
    }
};

int main()
{
    using namespace std::chrono_literals;

    SyncQueue<int> sq;

    std::thread consumer([&sq]()
    {
        std::cout << "consumer" << std::endl;

        for(;;)
        {
            std::cout << sq.deque() << std::endl;
        }
    });

    std::thread provider([&sq]()
    {
        std::this_thread::sleep_for(1s);
        sq.enque(1);
        std::this_thread::sleep_for(3s);
        sq.enque(2);
        std::this_thread::sleep_for(5s);
        sq.enque(3);
    });

    consumer.join();

    return 0;
}