摘自:C++ Concurrency in Action
使用条件变量进行线程同步
#include <thread>
#include <mutex>
#include <iostream>
#include <chrono>
#include <condition_variable>
#include <queue>
typedef int thread_id;
static int const QUEUE_MAX_SIZE = 500;
std::queue<thread_id> msg_queue;
std::mutex mtx;
std::condition_variable cv;
void get_msg(void)
{
while(true)
{
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck, []{return !msg_queue.empty();});
thread_id id = msg_queue.front();
msg_queue.pop();
std::cout << "real id " << std::this_thread::get_id() << " ,thread_id: " << id << std::endl;
}
}
void send_msg()
{
thread_id id = 0;
std::cout << "begin to product msg" << std::endl;
while(true)
{
id++;
std::unique_lock<std::mutex> lck(mtx);
if(msg_queue.size() < QUEUE_MAX_SIZE)
{
msg_queue.push(id);
std::cout << "msg pushed to queue: " << id << std::endl;
cv.notify_one();
}
}
}
int main(void)
{
std::thread produce_thread(send_msg);
std::thread threads[10];
for(int i=0; i<10; i++)
{
threads[i] = std::thread(get_msg);
}
produce_thread.join();
for(int i=0; i<10; i++)
{
threads[i].join();
}
return 0;
}
使用类封装后的形式:
#include <queue>
#include <mutex>
#include <memory>
#include <condition_variable>
#include <iostream>
#include <thread>
#include <chrono>
template <typename T>
class threadsafe_queue
{
public:
threadsafe_queue()
{
}
threadsafe_queue(const threadsafe_queue& other)
{
std::lock_guard<std::mutex> lck(mtx);
data_queue = other.data_queue;
}
void Push(T new_value)
{
std::lock_guard<std::mutex> lck(mtx);
data_queue.push(new_value);
data_cond.notify_one(); //通知
}
void wait_and_pop(T& value)
{
std::unique_lock<std::mutex> lck(mtx);
//捕获列表: [this]捕获当前类的this指针,让lambda表达式拥有和当前类成员同样的访问权限,可以修改类的成员变量,使用类的成员函数。
data_cond.wait(lck, [this]{return !data_queue.empty();});
value = data_queue.front();
data_queue.pop();
}
std::shared_ptr<T> wait_and_pop()
{
std::unique_lock<std::mutex> lck(mtx);
data_cond.wait(lck, [this]{return !data_queue.empty();});
std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
data_queue.pop();
return res;
}
bool try_pop(T& value)
{
std::lock_guard<std::mutex> lck(mtx);
if(data_queue.empty())
{
return false;
}
value = data_queue.front();
data_queue.pop();
return true;
}
std::shared_ptr<T> try_pop()
{
std::lock_guard<std::mutex> lck(mtx);
if(data_queue.empty())
{
return std::shared_ptr<T>();
}
std::shared_ptr<T> res(std::make_shared<T> (data_queue.front()));
data_queue.pop();
return res;
}
bool empty() const
{
std::lock_guard<std::mutex> lck(mtx);
return data_queue.empty();
}
private:
mutable std::mutex mtx;
std::queue<T> data_queue;
std::condition_variable data_cond;
};
struct msg
{
int data;
};
static threadsafe_queue<msg> msg_queue;
void func(void)
{
while(true)
{
std::shared_ptr<msg> ptr = msg_queue.wait_and_pop();
std::cout << "msg.data: " << (*ptr).data << std::endl;
}
}
int main()
{
std::thread th(func);
int count = 0;
while(true)
{
struct msg tmp_msg;
tmp_msg.data = ++count;
msg_queue.Push(tmp_msg);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
th.join();
return 0;
}