c++多线程的总结

头文件

#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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值