1.call_once的使用
在多线程编程中,有时某个任务只需要执行一次,此时可以用C++11中的std::call_once函数配合std::once_flag来实现。如果多个线程需要同时调用某个函数,std::call_once可以保证多个线程对该函数只调用一次。
#include<iostream>
#include<mutex>
#include<thread>
using namespace std;
once_flag init_flag;
void init()
{
cout << "data has inited" << endl;
}
void fun()
{
call_once(init_flag, init);
}
int main()
{
thread t1(fun);
thread t2(fun);
t1.join();
t2.join();
system("pause");
return 0;
}
2.shared_mutex
C++14提供了shared_mutex来解决读者-写者问题,也就是读写锁,和普通锁不一样,读写锁同时只能有一个写者或多个读者,但不能同时既有读者又有写者,读写锁的性能一般比普通锁要好。
shared_mutex g_mutex;
std::string g_str;
void readLoop()
{
while (true) {
this_thread::sleep_for(chrono::milliseconds(100));
g_mutex.lock_shared();
cout << g_str;
g_mutex.unlock_shared();
}
}
void writeLoop()
{
int number = 0;
while (true) {
this_thread::sleep_for(chrono::milliseconds(100));
g_mutex.lock();
g_str = to_string(number++)+"\n";
g_mutex.unlock();
}
}
int main()
{
thread(writeLoop).detach();
thread(readLoop).detach();
thread(readLoop).detach();
system("pause");
}
3.多线程 利用条件变量实现线程安全的队列
背景:标准STL库的队列queue是线程不安全的。 利用条件变量(Condition variable)简单实现一个线程安全的队列
#include <queue>
#include <memory>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include <thread>
template<typename T>
class threadsave_queue{
private:
mutable std::mutex mut;//必须是mutable,因为empty是const方法,但是要锁mut,锁操作就是改变操作
std::queue<T> data_queue;
std::condition_variable data_cond;
public:
threadsave_queue(){}
threadsave_queue(threadsave_queue const& other){
std::lock_guard<std::mutex> lk(other.mut);
data_queue = other.data_queue();
}
void push(T new_value){
std::lock_guard<std::mutex> lk(mut);
data_queue.push(new_value);
data_cond.notify_one();
}
void wait_and_pop(T& value){
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, [this]{return !data_queue.empty();});
value = data_queue.front();
data_queue.pop();
}
std::shared_ptr<T> wait_and_pop(){
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, [this]{return !data_queue.empty();});
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> lk(mut);
return data_queue.empty();
}
};
void make_data(threadsave_queue<int>& tq, int val){
tq.push(val);
}
void get_data1(threadsave_queue<int>& tq, int& d1){
tq.wait_and_pop(d1);
}
void get_data2(threadsave_queue<int>& tq, int& d1){
auto at = tq.wait_and_pop();
d1 = *at;
}
int main(){
threadsave_queue<int> q1;
int d1;
std::thread t1(make_data, std::ref(q1), 10);
std::thread t2(get_data1, std::ref(q1),std::ref(d1));
t1.join();
t2.join();
std::cout << d1 << std::endl;
std::thread t3(make_data, std::ref(q1), 20);
std::thread t4(get_data2, std::ref(q1),std::ref(d1));
t3.join();
t4.join();
std::cout << d1 << std::endl;
q1.empty();
}
4.packaged_task使用介绍
packaged_task类模板也是定义于future头文件中,它包装任何可调用 (Callable) 目标,包括函数、 lambda 表达式、 bind 表达式或其他函数对象,使得能异步调用它,其返回值或所抛异常被存储于能通过 std::future 对象访问的共享状态中。简言之,将一个普通的可调用函数对象转换为异步执行的任务。
#include <iostream> // std::cout
#include <thread> // std::thread
#include <chrono>
#include <future>
using namespace std;
//普通函数
int Add(int x, int y)
{
return x + y;
}
void task_lambda()
{
//包装可调用目标时lambda
packaged_task<int(int,int)> task([](int a, int b){ return a + b;});
//仿函数形式,启动任务
task(2, 10);
//获取共享状态中的值,直到ready才能返回结果或者异常
future<int> result = task.get_future();
cout << "task_lambda :" << result.get() << "\n";
}
void task_thread()
{
//包装普通函数
std::packaged_task<int (int,int)> task(Add);
future<int> result = task.get_future();
//启动任务,非异步
task(4,8);
cout << "task_thread :" << result.get() << "\n";
//重置共享状态
task.reset();
result = task.get_future();
//通过线程启动任务,异步启动
thread td(move(task), 2, 10);
td.join();
//获取执行结果
cout << "task_thread :" << result.get() << "\n";
}
int main(int argc, char *argv[])
{
task_lambda();
task_thread();
return 0;
}
5.多线程 等待一次性事件 std::promise用法
std::promise用来包装一个值将数据和future绑定起来,为获取线程函数的某个值获取便利,取值是间接通过promise内部提供的future来获取的。promise的主要目的是提供一个”Set”操作,和future的get()对应
#include<iostream>
#include<future>
#include<thread>
using namespace std;
using namespace std::this_thread;
using namespace std::chrono;
//费时操作
void work(promise<int> & prom)
{
cout << "开始计算!" << endl;
sleep_for(seconds(3));
//promise设置结果值
cout << "计算完成!" << endl;
prom.set_value(123);//设置结果,future会get到
}
int main()
{
//定义一个promise
promise<int> prom;
//future和promise搭配使用,类似于aynsc
future<int> result = prom.get_future();
thread t1(work , ref(prom));
t1.detach();
int sum = result.get();
cout << "获取结果:" << sum << endl;
system("pause");
return 0;
}