头文件
#include <thread> // 多线程
#include <atomic> // 原子量
#include <mutex> // 互斥锁
#include <condition_variable> // 条件变量
#include <future> // 线程结果交付
#include <chrono> // 精确时间类
在 Linux 下编译需要手动加入编译选项 -lpthread。
多线程
// Thread 多线程
thread th(func, param1, param2, ...); // 定义一个线程 th, 使用函数 func, 参数放后面
th.join(); // 主线程堵塞,等待 th 执行完毕
th.detach(); // 子线程脱离成为孤儿线程,从此无关也无法通信
this_thread::sleep_for(chrono::seconds(x)); // 当前线程睡眠 x 秒
this_thread::yield(); // 让出当前线程的 CPU
this_thread::get_id(); // 获取当前线程的 ID
thread::hardware_concurrency(); // 获取当前 CPU 核心数量
// Mutex 互斥锁
mutex lock0; // 定义一个互斥量,初始为解锁状态
lock0.lock(); // 互斥量锁定
lock0.unlock() // 互斥量解锁
// 封装后的互斥锁
{ lock_guard<mutex> lock {lock0}; } // 进入代码段自动对 lock0 上锁,离开代码段自动解锁,坐待代码段互斥
{ unique_lock<mutex> lock {que_lock}; } // 代码段有效的锁,支持随时上锁解锁,离开代码段自动解锁
// 条件变量
condition_variable cv; // 定义条件变量
cv.wait(lock, <condi>); // 当被激活 & 满足条件 <condi> 时继续执行,否则忙等
cv.notify_one(); cv.notify_all(); // 激活条件变量
// Atomic 原子量
// * 定义原子量并初始化为清空
atomic_flag lock0 = ATOMIC_FLAG_INIT;
while(lock0.test_and_set()){}; // 盲等置原子量清空,然后再设置
lock0.clear();
// * 定义整型原子量(对其他复杂类型支持不好)
atomic<int> vari0(0);
// exchange(v) 获取原子量值并且设置为新值 v
print("%d\n", vari0.exhange(0)); // 输出原子量当前值并清零
// 对于整型原子量可以使用操作:+= -= &= |= ^= ++ --
vari0+=1; vari0-=1; vari0++; vari0--;
// load(); store(v); 获取原子量值 / 设置原子量值为 v
printf("%d\n", vari0.load()); vari0.store(0);
异步
// 参数传递
promise<T> promiseObj; // 定义一个参数,在未来会被赋值
future<T> futureObj = promiseObj.get_future(); // 获取一定会被赋值的参数未来的值
// 与多线程一同使用
void clear_func(promise<int>& ret){ ret.set_value(0); }
thread(clear_func, ref(promiseObj));
printf("%d\n", futureObj.get());
// 与异步一起使用
int clear_func(){ return 0; }
future<int> futureObj = async(clear_func);
printf("%d\n", futureObj.get());
// 获取 future 量的状态,状态量有三种:future_status::timeout、future_status::deferred、future_status::ready 分别对应超时、未开始和已完成
future_status status = futureObj.wait_for(std::chrono::seconds(1));
以上转载自喂你脚下有坑的博客
.
.
.
.
.
以下大部分来自《c++并发编程实战》
可接受超时的函数表
每个原子类型的可接受操作表
一个使用条件变量的线程安全的队列(完整版)
#include <queue>
#include <memory>
#include <mutex>
#include <condition_variable>
template<typename T>
class threadsafe_queue {
private:
mutable std::mutex mut; // 1 互斥量必须是可变的
std::queue<T> data_queue;
std::condition_variable data_cond;
public:
threadsafe_queue() {}threadsafe_queue(threadsafe_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 try_pop(T& value) {
std::lock_guard<std::mutex> lk(mut);
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> lk(mut);
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> lk(mut);
return data_queue.empty();
}
};
线程安全的哈希表
#include <vector>
#include <memory>
#include <mutex>
#include <functional>
#include <list>
#include <utility>
#include <shared_mutex>
template<typename Key,typename Value,typename Hash=std::hash<Key> >
class threadsafe_lookup_table
{
private:
class bucket_type
{
private:
typedef std::pair<Key,Value> bucket_value;
typedef std::list<bucket_value> bucket_data;
typedef typename bucket_data::iterator bucket_iterator;
bucket_data data;
mutable std::shared_mutex mutex;
bucket_iterator find_entry_for(Key const& key) const
{
return std::find_if(data.begin(),data.end(),
[&](bucket_value const& item)
{return item.first==key;});
}
public:
Value value_for(Key const& key,Value const& default_value) const
{
std::shared_lock<std::shared_mutex> lock(mutex);
bucket_iterator const found_entry=find_entry_for(key);
return (found_entry==data.end())?
default_value : found_entry->second;
}
void add_or_update_mapping(Key const& key,Value const& value)
{
std::unique_lock<std::shared_mutex> lock(mutex);
bucket_iterator const found_entry=find_entry_for(key);
if(found_entry==data.end())
{
data.push_back(bucket_value(key,value));
}
else
{
found_entry->second=value;
}
}
void remove_mapping(Key const& key)
{
std::unique_lock<std::shared_mutex> lock(mutex);
bucket_iterator const found_entry=find_entry_for(key);
if(found_entry!=data.end())
{
data.erase(found_entry);
}
}
};
std::vector<std::unique_ptr<bucket_type> > buckets;
Hash hasher;
bucket_type& get_bucket(Key const& key) const
{
std::size_t const bucket_index=hasher(key)%buckets.size();
return *buckets[bucket_index];
}
public:
typedef Key key_type;
typedef Value mapped_type;
typedef Hash hash_type;
threadsafe_lookup_table(
unsigned num_buckets=19, Hash const& hasher_=Hash()):
buckets(num_buckets),hasher(hasher_)
{
for(unsigned i=0;i<num_buckets;++i)
{
buckets[i].reset(new bucket_type);
}
}
threadsafe_lookup_table(threadsafe_lookup_table const& other)=delete;
threadsafe_lookup_table& operator=(
threadsafe_lookup_table const& other)=delete;
Value value_for(Key const& key,
Value const& default_value=Value()) const
{
return get_bucket(key).value_for(key,default_value);
}
void add_or_update_mapping(Key const& key,Value const& value)
{
get_bucket(key).add_or_update_mapping(key,value);
}
void remove_mapping(Key const& key)
{
get_bucket(key).remove_mapping(key);
}
};
for_each并行版
#include <future>
#include <algorithm>
struct join_threads
{
join_threads(std::vector<std::thread>&)
{}
};
template<typename Iterator,typename Func>
void parallel_for_each(Iterator first,Iterator last,Func f)
{
unsigned long const length=std::distance(first,last);
if(!length)
return;
unsigned long const min_per_thread=25;
unsigned long const max_threads=
(length+min_per_thread-1)/min_per_thread;
unsigned long const hardware_threads=
std::thread::hardware_concurrency();
unsigned long const num_threads=
std::min(hardware_threads!=0?hardware_threads:2,max_threads);
unsigned long const block_size=length/num_threads;
std::vector<std::future<void> > futures(num_threads-1);
std::vector<std::thread> threads(num_threads-1);
join_threads joiner(threads);
Iterator block_start=first;
for(unsigned long i=0;i<(num_threads-1);++i)
{
Iterator block_end=block_start;
std::advance(block_end,block_size);
std::packaged_task<void(void)> task(
[=]()
{
std::for_each(block_start,block_end,f);
});
futures[i]=task.get_future();
threads[i]=std::thread(std::move(task));
block_start=block_end;
}
std::for_each(block_start,last,f);
for(unsigned long i=0;i<(num_threads-1);++i)
{
futures[i].get();
}
}
一个简单的线程池
#include <deque>
#include <future>
#include <memory>
#include <functional>
#include <iostream>
#include <iostream>
class function_wrapper
{
struct impl_base {
virtual void call()=0;
virtual ~impl_base() {}
};
std::unique_ptr<impl_base> impl;
template<typename F>
struct impl_type: impl_base
{
F f;
impl_type(F&& f_): f(std::move(f_)) {}
void call() { f(); }
};
public:
template<typename F>
function_wrapper(F&& f):
impl(new impl_type<F>(std::move(f)))
{}
void call() { impl->call(); }
function_wrapper(function_wrapper&& other):
impl(std::move(other.impl))
{}
function_wrapper& operator=(function_wrapper&& other)
{
impl=std::move(other.impl);
return *this;
}
function_wrapper(const function_wrapper&)=delete;
function_wrapper(function_wrapper&)=delete;
function_wrapper& operator=(const function_wrapper&)=delete;
};
class thread_pool
{
public:
std::deque<function_wrapper> work_queue;
template<typename FunctionType>
std::future<typename std::result_of<FunctionType()>::type>
submit(FunctionType f)
{
typedef typename std::result_of<FunctionType()>::type result_type;
std::packaged_task<result_type()> task(std::move(f));
std::future<result_type> res(task.get_future());
work_queue.push_back(std::move(task));
return res;
}
// rest as before
};
线程的启动和中断
#include <thread>
#include <future>
#include <mutex>
#include <condition_variable>
#include <queue>
template<typename T>
class threadsafe_queue
{
private:
std::mutex mut;
std::queue<T> data_queue;
std::condition_variable data_cond;
public:
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();
}
};
class interrupt_flag
{
public:
void set(); //启动
bool is_set() const; //是否启动了
};
thread_local interrupt_flag this_thread_interrupt_flag;
class interruptible_thread
{
std::thread internal_thread;
interrupt_flag* flag;
public:
template<typename FunctionType>
interruptible_thread(FunctionType f)
{
std::promise<interrupt_flag*> p;
internal_thread=std::thread([f,&p]{
p.set_value(&this_thread_interrupt_flag);
f();
});
flag=p.get_future().get();
}
void interrupt()
{
if(flag)
{
flag->set();
}
}
};
并发对队列调用pop()和push()的测试
void test_concurrent_push_and_pop_on_empty_queue()
{
threadsafe_queue<int> q; //环境设置代码中创建空队列
std::promise<void> go,push_ready,pop_ready;//为准备状态创建promise对象
std::shared_future<void> ready(go.get_future());//为go信 号获取一个 std::shared_future 对象
std::future<void> push_done; //创建future用来表示线程是否结束
std::future<int> pop_done;
try
{
push_done=std::async(std::launch::async, //保证每个任务在自己的线程上完成
[&q,ready,&push_ready]()
{
push_ready.set_value();
ready.wait();
q.push(42);
}
);
pop_done=std::async(std::launch::async, //保证每个任务在自己的线程上完成
[&q,ready,&pop_ready]()
{
pop_ready.set_value();
ready.wait();
return q.pop(); //通过future返回检索值
}
);
push_ready.get_future().wait(); //等待所有线程的信号
pop_ready.get_future().wait();
go.set_value(); //提示所有线程可以开始进行测试了
push_done.get();
assert(pop_done.get()==42); //异步调用等待线程完成
assert(q.empty());
}
catch(...)
{
go.set_value();
throw;
}
}