簡體   English   中英

兩個線程之間的同步隊列

[英]Sync queue between two threads

這是一個簡單的程序,它有一個 function 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);
        }

    }
}

您的代碼包含種族 -對我而言,它已崩潰; 兩個線程都可能在修改共享隊列。 (此外,您正在使用char i循環獲得最多1000的值-可能不是一個好主意。)

您應該使用std::mutex保護共享隊列,並使用std::condition_variable通知有理由檢查隊列。

具體來說,您應考慮以下因素(這對於生產者消費者來說是很常見的):

  1. 僅在保持互斥時訪問隊列。

  2. 使用條件變量來通知您已將某些內容推入其中。

  3. 使用條件變量可以指定何時有條件繼續處理的條件。

這是您的代碼的重寫:

#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();
}

我的同步隊列類示例及其用法:

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;
}
/* Here I have a code snippate with Separate class for Producing and Consuming along with buffer class */ #include <iostream> #include <mutex> #include <condition_variable> #include <thread> #include <deque> #include <vector> using namespace std; mutex _mutex_1,_mutex_2; condition_variable cv; template <typename T> class Queue { deque<T> _buffer; const unsigned int max_size = 10; public: Queue() = default; void push(const T& item) { while(1) { unique_lock<mutex> locker(_mutex_1); cv.wait(locker,[this](){ return _buffer.size() < max_size; }); _buffer.push_back(item); locker.unlock(); cv.notify_all(); return; } } T pop() { while(1) { unique_lock<mutex> locker(_mutex_1); cv.wait(locker,[this](){ return _buffer.size() > 0; }); int back = _buffer.back(); _buffer.pop_back(); locker.unlock(); cv.notify_all(); return back; } } }; class Producer { Queue<int>* _buffer; public: Producer(Queue<int>* _buf) { this->_buffer = _buf; } void run() { while(1) { auto num = rand()%100; _buffer->push(num); _mutex_2.lock(); cout<<"Produced:"<<num<<endl; this_thread::sleep_for(std::chrono::milliseconds(50)); _mutex_2.unlock(); } } }; class Consumer { Queue<int>* _buffer; public: Consumer(Queue<int>* _buf) { this->_buffer = _buf; } void run() { while(1) { auto num = _buffer->pop(); _mutex_2.lock(); cout<<"Consumed:"<<num<<endl; this_thread::sleep_for(chrono::milliseconds(50)); _mutex_2.unlock(); } } }; void client() { Queue<int> b; Producer p(&b); Consumer c(&b); thread producer_thread(&Producer::run, &p); thread consumer_thread(&Consumer::run, &c); producer_thread.join(); consumer_thread.join(); } int main() { client(); return 0; }

暫無
暫無

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

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