![](/img/trans.png)
[英]What is the correct way to sync variables between two threads in C++?
[英]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
通知有理由檢查隊列。
具體來說,您應考慮以下因素(這對於生產者消費者來說是很常見的):
僅在保持互斥時訪問隊列。
使用條件變量來通知您已將某些內容推入其中。
使用條件變量可以指定何時有條件繼續處理的條件。
這是您的代碼的重寫:
#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.