C++并发编程学习笔记
//
// main.cpp
// test1
//
// Created by sofard on 2018/12/27.
// Copyright © 2018年 dapshen. All rights reserved.
//
#include <iostream>
#include <thread>
#include <future> //异步网络请求类似
#include <utility>
#include <vector>
#include <numeric>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <list>
#include <algorithm>
#include <deque>
#include <stack>
#include <exception>
#include <memory> // shared_ptr<>
#include <map>
#include <boost/thread/shared_mutex.hpp>
#include <queue>
#include <chrono>
#include <atomic>
void hellow()
{
std::cout << "hellow,concurrent!" << std::endl;
}
int main(int argc, const char * argv[]) {
// insert code here...
std::thread th1{hellow};
th1.join();
//std::cout << "Hello, World!\n";
return 0;
}
/////////////////////
void do_something(int i=8)
{
}
void do_something_else()
{
}
class background_task
{
public:
void operator()() const
{
do_something();
do_something_else();
}
};
background_task back_init1;
std::thread my_thread2(background_task);
std::thread my_thread3(background_task()); //函数声明
std::thread my_thread4 {background_task()}; //用大括号初始化还是挺好的
std::thread my_thread5([]{do_something();do_something_else();
}); //使用lamada表达式也可以
//detach()分离
//join()等待线程完成,把启动线程全部开启
//join,需要细心挑选运行的位置
////////////
void do_something()
{
}
struct my_func{
int& i;
my_func(int& _i):i(_i){};
void operator()()
{
for(unsigned j =0 ;j< 100000; ++j)
do_something(i);
}
};
////RAII 资源包裹类解决join之前抛出异常
class thread_guard
{
std::thread& t;
public:
explicit thread_guard(std::thread& _t):t(_t)
{}
~thread_guard()
{
if(t.joinable())
{
t.join();
}
}
thread_guard(thread_guard const&) = delete;
thread_guard& operator=(const thread_guard &) = delete;
};
void do_something_in_main()
{
}
void f()
{
int some_local_state =0;
my_func new_fun(some_local_state);
std::thread th1{new_fun};
thread_guard self_raii(th1);
do_something_in_main(); //若抛出异常
//self_raii 一定会析构,一定会join启动
}
///deatch()实现多文档编辑功能
class user_command
{
public:
int type;
};
const int open_new_document =1;
user_command get_user_input()
{
return user_command();
}
std::string ss1="123";
std::string& get_filename()
{
return ss1;
}
void process_user_input(const user_command&){}
void edit_document(const std::string& file_name )
{
//初始化ui
bool flag_end =false;
while(flag_end)
{
user_command new_cmd = get_user_input();
if(new_cmd.type == open_new_document )
{
const std::string file_n = get_filename();
std::thread th8{edit_document,file_n};
th8.detach();
}
else
{
process_user_input(new_cmd);
}
}
}
/////////线程传参数
class widget_data
{
};
void process_widget_data(widget_data&){}
void my_func90(int i,const widget_data& s);
void oops(int some_param)
{
widget_data data;
std::thread th9(my_func90,3,data);
//简单参数拷贝复制,存在线程中修改的是临时数据的情况
std::thread th10(my_func90,3,std::ref(data));
//使用ref提升为引用
th9.join();
process_widget_data(data);
}
//第二种高级
class X
{
public:
void do_lengthy_work();
};
X my_x;
//另外一种传递函数,再传递拥有的对象的方法,第三个参数开始是函数参数
//参数可以移动,不能拷贝 (unique_ptr<> 移动构造函数,移动拷贝函数等)
//使用std::move()
/*
std::thread() 和 std::unique_ptr<>一样 每个实例占有一部分资源所有权,资源不会被复制,只能转移
*/
std::thread th11(&X::do_lengthy_work,&my_x);
////////转移线程所有权
void some_function()
{}
void some_function_else()
{}
void fuck_10_test()
{
std::thread th12{some_function};
std::thread th13=std::move(th12);
th12 =std::thread(some_function_else);//
std::thread th14;
th14=std::move(th13);
//此时th12有资源,th14也有资源
th12=std::move(th14); //th12会调用terminate(),析构掉,程序异常
}
/////////量产固定线程代码
void do_work(unsigned id){};
void init_more_thread()
{
std::vector<std::thread> threads;
for(unsigned i=0;i<20;++i)
threads.push_back(std::thread(do_work,i));
std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
}
//////升级1:运行时决定线程的数量
int number_thread = std::thread::hardware_concurrency();//获取参考
//自己封装下std::accumulate 单线程求和
template<typename Iterator,typename T>
struct accumulate_block
{
void operator()(Iterator first,Iterator last,T& result)
{
result =std::accumulate(first,last,result);
}
};
void test11()
{
accumulate_block<std::vector<int>::iterator, int> add_t;
std::vector<int> jiashu;
int jie;
add_t(jiashu.begin(), jiashu.end(), jie);
std::accumulate(jiashu.begin(), jiashu.end(),jie);
}
//多线程求和,不带异常处理
template<typename Iterator,typename T>
T parallel_accumulate(Iterator first,Iterator last,T init)
{
unsigned long const length =std::distance(first, last);
if(!length)
return init;
//每个线程最少25个数据
unsigned long const min_per_thread = 25;
unsigned long const max_thread =(length + min_per_thread -1)/min_per_thread;
//获取硬件参考线程数量
unsigned long const hardware_thread = std::thread::hardware_concurrency();
unsigned long const num_thread =
std::min(hardware_thread != 0 ? hardware_thread : 2,max_thread);
//每个线程分配的数量
unsigned long const block_size = length/num_thread;
std::vector<T> results(number_thread);
std::vector<std::thread> threads(number_thread);
Iterator block_start =first;
for(unsigned long i=0;i<number_thread-1;++i)
{
Iterator block_end =block_start;
std::advance(block_end, block_size);
//每次都传参到线程中,能否有其他方式返回其运算结果??
threads[i]=std::thread
(accumulate_block<Iterator,T>(),block_start,block_end,std::ref(results[i]));
block_start=block_end;
}
accumulate_block<Iterator,T>()(block_start,last,std::ref(results[number_thread-1]));
//等待累加完成
std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
return std::accumulate(results.begin(), results.end(), init);
};
void test_para()
{
std::vector<int> jiashu;
int jie;
//函数模板会自动推断参数类型,也可以给定参数类型
jie=parallel_accumulate<>(jiashu.begin(),jiashu.end(),0);
}
/////识别线程
//标识类型为std::thread::id ,可以比较复制,做很多事情
//////////第三章 线程间共享数据
//race condition,操作非原子
/*
1.保护机制,只有修改的线程能看到中间状态 c++标准库机制
2.修改数据结构和不变量设计,保证结构完成不可分割的变化,lock-free programming
3.软件事物编程(STM),类似于数据库,提交,回滚等
*/
//3.2 使用互斥量保护共享数据,这里使用的是RAII互斥量
class test_lock
{
private:
std::list<int> some_list;
std::mutex some_mutex;
public:
void add_to_list(int new_value)
{
std::lock_guard<std::mutex> guard(some_mutex);
some_list.push_back(new_value);
}
bool list_contains(int value_to_find){
std::lock_guard<std::mutex> guard(some_mutex);
return std::find(some_list.begin(), some_list.end(), value_to_find) == some_list.end();
}
//接口设计需要谨慎,不能留 成员的指针或者引用
};
//3.22 精心组织代码保护共享数据
//切勿将保护数据的指针或引用传递到互斥锁作用域之外,亦或是参数形式传递到用户提供的函数
class some_data{
int a;
std::string b;
public:
void do_something(){};
};
//对data类,通过类似于RAII的包裹,同时实现对data类所有操作的并发控制 (本意如此,可惜可以通过指针盗取data数据,绕过包裹)
class data_wrapper{
some_data data;
std::mutex m;
public:
template<typename Function>
void process_data(Function func){
std::lock_guard<std::mutex> l(m);
func(data); //这尼玛什么鬼语法
}
};
some_data * unprotected;
void malicious_function(some_data &th){
unprotected=&th;
}
data_wrapper x;
void foo100(){
//给每一个函数调用加锁
x.process_data(malicious_function);
unprotected->do_something();
}
//3.2.3 发现接口内在的条件竞争
/*
考虑一个stack ,empty(),top(),pop()接口之间存在竞争,如何解决?
构造函数分配空间时抛出bad_alloc异常,如何解决?给类自定义该异常处理函数,返回再分配..
*/
template <typename T,typename Container = std::deque<T> >
class my_stack
{
public:
//使用deque<T>来初始化stack<T>
explicit my_stack(const Container& ){};
//转移构造函数
explicit my_stack(Container && = Container());
//模板构造函数
template <class Alloc>
explicit my_stack(const Alloc&);
template <class Alloc>
my_stack(const Container&,const Alloc&);
template <class Alloc>
my_stack(const Container&& ,const Alloc&);
template <class Alloc>
my_stack(my_stack&&,const Alloc&);
//const 成员函数
bool empty() const;
size_t size() const;
//const成员函数 与 非const重载
T& top();
const T& top() const;
//右值引用,传参数时,转移所有权
void push(const T&);
void push(T&&);
void pop();
void swap(my_stack&&);
};
//empty,与size的结果不可靠,调用后,数据可能被改掉
void visit_stack()
{
std::stack<int> s;
if(!s.empty()){
int const value =s.top();
// top() 与empty存在竞争
s.pop();
do_something(value);
}
}
//假设现在将stack里面的任务分摊给多个线程,那么top()可能获取到一样 top和pop存在竞争
//解决办法:
//若将top和pop合并,返回栈顶元素,但是当拷贝大数据时,可能抛出异常(bad_alloc),栈顶元素会丢失..
/*
新问题解决办法:
1.可以先分配大数据,再传入引用,移动拷贝
使用std::is_nothrow_copy_constructible<<#class _Tp#>>
std::is_nothrow_move_constructible<<#class _Tp#>>等编译选项
2.返回指向弹出值的指针(使用共享指针)
内部类型 int float 的内存管理开销相对比较大,可能不划算
3.组合使用前面方法
*/
//线程安全的stack
struct empty_stack:std::exception
{
const char* what() const throw();
};
template <typename T>
class threadsafe_stack {
std::stack<T> data;
mutable std::mutex m;
public:
threadsafe_stack(){};
threadsafe_stack(const threadsafe_stack& other){
std::lock_guard<std::mutex> lock(other.m);
data=other.data;
};
threadsafe_stack& operator=(const threadsafe_stack&) = delete;
void push(T new_value){
std::lock_guard<std::mutex> lock(m);
data.push(new_value);
};
std::shared_ptr<T> pop()
{
std::lock_guard<std::mutex> lock(m);
if(!data.empty()) throw empty_stack(); //检查栈是否为空
std::shared_ptr<T> const res(std::make_shared<T>(data.top()));
data.pop();
return res;
};
void pop(T& value)
{
std::lock_guard<std::mutex> lock(m);
if(!data.empty()) throw empty_stack(); //检查栈是否为空
value=data.top();
data.pop();
};
bool empty() const{
std::lock_guard<std::mutex> lock(m);
return data.empty();
};
};
//3.2.4死锁
/*
避免死锁:A,B 2把锁, 按照固定的顺序上锁,解锁
*/
//交换操作中使用 std::lock() 和std::lock_guard()
class some_big_object
{};
void swap(some_big_object& lhs,some_big_object & rhs)
;
class X_2
{
some_big_object some_detail;
std::mutex m;
public:
X_2(some_big_object const& sd):some_detail(sd){};
friend void swap(X_2 lhs,X_2& rhs)
{
if(&lhs==&rhs)
return ;
std::lock(lhs.m,rhs.m);//可能抛出异常,抛出异常会自动解锁
//std::adopt_lock()表示对象已经上锁,不用上新锁
std::lock_guard<std::mutex> lock_a(lhs.m,std::adopt_lock);
std::lock_guard<std::mutex> lock_b(rhs.m,std::adopt_lock);
/* 使用unique_lock时的代码
std::unique_lock<std::mutex> la(lhs.m,std::defer_lock);
std::unique_lock<std::mutex> lb(rhs.m,std::defer_lock);
std::lock(la,lb);
*/
swap(lhs.some_detail,rhs.some_detail);
}
};
//3.2.5避免死锁的进阶指导
/*
建议1:获取到一个锁后,尽量不去请求其他的锁
若要请求多个锁,使用std::lock(....)一次性获取
建议2:
避免在持有锁时,调用用户提供的代码(其他人写得代码)
使用固定顺序获取锁
定义遍历的顺序
对应用分层,解耦
*/
//层次避免死锁
//定义层次锁
class hierarchical_mutex
{
std::mutex internal_mutex;
unsigned long const hierarchy_value;
unsigned long previous_hierarchy_value;
static thread_local unsigned long this_thread_hierarchy_value;
void check_for_hierarchy_violation()
{
if(this_thread_hierarchy_value <= hierarchy_value)
{
throw std::logic_error("mutex hierarchy violated");
}
}
void update_hierarchy_value()
{
previous_hierarchy_value = this_thread_hierarchy_value;
this_thread_hierarchy_value = hierarchy_value;
}
public:
explicit hierarchical_mutex(unsigned long value):
hierarchy_value(value),previous_hierarchy_value(0)
{
}
void lock()
{
check_for_hierarchy_violation();
internal_mutex.lock();
update_hierarchy_value();
}
void unlock()
{
this_thread_hierarchy_value = previous_hierarchy_value ;
internal_mutex.unlock();
}
bool try_lock()
{
check_for_hierarchy_violation();
if(!internal_mutex.try_lock())
return false;
update_hierarchy_value();
return true;
}
};
thread_local unsigned long hierarchical_mutex::this_thread_hierarchy_value(ULONG_MAX);
//每一个实例锁都有一个自己当前的层次,每个线程维护一个static层次 表示当前线程所在的层次
//应用分层,定义出所有每层可能上锁的互斥量,给予层级初值
//上锁:当前线程层次(跑到最底层的线程) < 当前上锁的层次 ,终止操作
hierarchical_mutex high_level_mutex(10000);
hierarchical_mutex low_level_mutex(5000);
//低层次的事情
int do_low_level_stuff();
int low_level_func(){
std::lock_guard<hierarchical_mutex> lk(low_level_mutex);
return do_low_level_stuff();
}
//高层次的事情
void high_level_stuff(int some_param);
void high_level_func(){
std::lock_guard<hierarchical_mutex> lk(high_level_mutex);
high_level_stuff(low_level_func());
}
//执行顺序由高到底,没问题
void thread_a(){
high_level_func();
}
hierarchical_mutex other_mutex(100);
void do_other_stuff();
void other_stuff(){
high_level_func();
do_other_stuff();
}
//先锁住100
//再视图访问10000层级时,10000层级可能被其他线程锁住,形成死锁
/*解决办法
自定义层次锁:当满足这种情况时,抛出异常,析构释放变量的时候,会释放100层次的锁
*/
void thread_b()
{
std::lock_guard<hierarchical_mutex> lk(other_mutex);
other_stuff();
}
///3.2.6 std::unique_lock---- 灵活的锁
//3.2.7不同域传递互斥量
/*
std::unique_lock<> 没有与自身相关的互斥量
*/
//函数get_lock()锁住了互斥量,然后准备数据,返回锁,将对数据的锁,转移给处理函数
void prepare_data();
std::unique_lock<std::mutex> get_lock()
{
extern std::mutex some_mutex;
std::unique_lock<std::mutex> lk(some_mutex);
prepare_data();
return lk; //lk被释放,但是先将所有权转移出去
}
void process_data()
{
std::unique_lock<std::mutex> lk(get_lock());
do_something(1);
//lk.unlock() 可以选择性的释放,lk在销毁前会自动释放
}
//3.2.8 锁的粒度 通过std::unique_lock控制
std::mutex the_mutex;
void get_and_process_data()
{
std::unique_lock<std::mutex> my_lock(the_mutex);
//准备数据操作,data1
my_lock.unlock();
//操作局部数据data1
//再次锁住
my_lock.lock();
//写数据操作
}//自动析构释放锁
//在比较操作符中一次锁定一个互斥量
class Y {
int some_detail;
mutable std::mutex m;
int get_detail() const
{
std::lock_guard<std::mutex> lock_a(m);
return some_detail;
}
public:
Y(int sd):some_detail(sd){};
friend bool operator==(const Y& lhs,const Y& rhs)
{
if(&lhs==&rhs)
return true;
int const lhs_value = lhs.get_detail();
int const rhs_value = rhs.get_detail();
return lhs_value == rhs_value;
}
};
///单例模式 std::once_flag std::call_once配合使用
class some_resource{
public:
void do_something();
};
std::shared_ptr<some_resource> resource_ptr;
std::once_flag resource_flag;
void init_resource()
{
resource_ptr.reset(new some_resource);
}
void foo()
{
//多线程运行时,该语句只会执行一次
std::call_once(resource_flag, init_resource);
resource_ptr->do_something();
}
//C++11 最安全的单例是 定义为函数static变量
////读写锁
//对于一个dns缓存,写得时候不能读,读得时候可以读
class dns_entry
{
public:
std::string eny;
};
class dns_cache
{
typedef std::map<std::string,dns_entry> hash_entry;
hash_entry entries;
mutable boost::shared_mutex entry_mutex;
public:
//使用读锁
dns_entry find_entry(std::string const & domain)
{
boost::shared_lock<boost::shared_mutex> lo(entry_mutex);
const hash_entry::const_iterator it = entries.find(domain);
return (it == entries.end()) ? dns_entry():it->second;
}
//使用写锁添加数据
void update_or_add_entry(const std::string& key,const dns_entry& value)
{
std::lock_guard<boost::shared_mutex> lo(entry_mutex);
entries[key]=value;
}
};
//嵌套锁即可重入锁,类多个成员函数相互调用,且每个函数都加锁的时候
//大佬们都不推荐使用可重入锁
void test_ul()
{
std::recursive_mutex mmm;
std::lock_guard<std::recursive_mutex> lk(mmm);
std::unique_lock<std::recursive_mutex> uk(mmm);
}
/////第四章 同步并发操作
//4.1 等待一个事件或其他条件
//条件变量:1个或多个线程等待条件的达成,条件变量与多个时间或者条件相关
//广播条件达成消息
void test_con(){
std::condition_variable cd1;
std::mutex mx1;
std::condition_variable_any cd_any;
//可以与任何满足mutex的变量配合使用
}
//使用条件变量做唤醒的代码
class data_chunk{
public:
std::string st;
void process_data_chunk()
{};
};
std::mutex mut;
std::queue<data_chunk> data_queue;
std::condition_variable data_cond;
bool more_data_to_prepare()
{
return true;
}
bool is_last_data_chunk(data_chunk& )
{
return false;
}
data_chunk prepare_data_chunk(){
return data_chunk();
};
void data_preparetion_thread()
{
while(more_data_to_prepare())
{
data_chunk const data = prepare_data_chunk();
std::lock_guard<std::mutex> lk(mut);
data_queue.push(data);
data_cond.notify_one();
}
}
void data_processing_thread()
{
while(true)
{
std::unique_lock<std::mutex> lk(mut);
//条件变量,以某个条件函数检测 某互斥量,条件不满足 加入休眠队列,同时释放锁
//条件满足,继续执行
data_cond.wait(lk,[]{return !data_queue.empty();});
data_chunk data= data_queue.front();
data_queue.pop();
lk.unlock(); //拿到数据立马放锁
data.process_data_chunk() ; // 处理数据
if(is_last_data_chunk(data))
break;
}
}
//4.1.2使用条件变量构建线程安全队列
//stl中的队列
template<class T,class Container = std::deque<T>>
class my_queue{
public:
explicit my_queue(Container const & );
explicit my_queue(Container && = Container());
template<class Alloc>
explicit my_queue(const Alloc&);
template<class Alloc>
my_queue(const Container&,const Alloc&);
template<class Alloc>
my_queue(Container&,const Alloc&);
template<class Alloc>
my_queue(my_queue&&,const Alloc&);
void swap(my_queue&);
//查询操作
bool empty() const;
size_t size() const;
const T& front() const;
T& back() ;
T& front() ;
const T& back() const;
//修改操作
void push(const T&);
void push(T&& );
void pop();
template<class ...Args>
void emplace(Args&&... args);
};
//线程安全的队列
template<typename T>
class threadsafe_queue
{
private:
std::mutex mut;
std::queue<T> local_queue;
std::condition_variable data_cond;
public:
threadsafe_queue();
threadsafe_queue(const threadsafe_queue&);
threadsafe_queue& operator=(const threadsafe_queue&) =delete;
void push(T& new_value)
{
std::lock_guard<std::mutex> lk(mut);
local_queue.push(new_value);
data_cond.notify_one();
};
//出队列,使用非条件变量出队列
bool try_pop(T& value);
std::shared_ptr<T> try_pop()
{
std::lock_guard<std::mutex> lk(mut);
if(local_queue.empty())
return std::shared_ptr<T>();
std::shared_ptr<T> res(std::make_shared<T>(local_queue.fornt()));
return res;
};
void wait_and_pop(T&value)
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk,[this]{return !local_queue.empty();});
value=local_queue.fornt();
local_queue.pop();
};
//返回只能指针版本,资源消耗稍微大一些
std::shared_ptr<T> wait_and_pop()
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk,[this]{return !local_queue.empty();});
//此处构造函数可能会抛出异常,将local_queue 结构改成 std::queue<shared_ptr<T>> 可以解决
std::shared_ptr<T> res(std::make_shared<T>(std::move(local_queue.front())));
local_queue.pop();
return res;
};
bool empty() const
{
std::lock_guard<std::mutex> lk(mut);
return local_queue.empty();
};
};
///使用期望等待,一次性事件 一次性,一次性,一次性
//带返回值的后台任务,比如网络请求
int find_the_answer_to_ltuae();
void do_other_stuff();
void mai_mm()
{
std::future<int> the_answer = std::async(find_the_answer_to_ltuae);
do_other_stuff();
std::cout<<"the answer is" << the_answer.get() <<std::endl;
}
struct X_i
{
void foo(int,std::string const&);
std::string bar(std::string const&);
};
X_i xi;
//通过地址+对象方式,启动异步带返回值任务
auto fi =std::async(&X_i::foo,&xi, 42,"hellow");
//仿函数
struct Y_i
{
double operator()(double);
};
Y_i yi;
auto f3 = std::async(Y_i(), 3.141);//隐含使用了移动构造函数
auto f4 = std::async(std::ref(yi), 2.718);
X_i baz(X_i&);
void qita()
{
auto f5=std::async(baz, std::ref(xi));
//async有额外的2个参数可供选择
//std::launch::async表明独立线程,
//std::launch::deferred表明线程在wait()或者get()后再运行
std::future<X_i> f6 =std::async(std::launch::async | std::launch::deferred,baz,std::ref(xi));
std::future<X_i> f7 =std::async(std::launch::deferred,baz,std::ref(xi));
f6.wait();
}
//4.2.2任务与期望
//对任务细节抽象
//当一个粒度较大的操作可以分解为独立的子任务时,每个子任务可以包含在一个
//std::packaged_task<函数签名>中,之后这个实例将传递到任务调度器或者线程池中
//std::packaged_task<>的特化-----局部类定义,任务带2个参数,返回string
template<>
class std::packaged_task<std::string(std::vector<char>* ,int)>
{
public:
template <typename Callable>
explicit packaged_task(Callable&& f);
std::future<std::string> get_future();
void operator()(std::vector<char>*,int); //()任务执行
};
//使用 std::packaged_tast 执行一个图形界面线程
std::mutex m_image;
std::deque<std::packaged_task<void()>> tasks;
bool gui_shutdown_message_received();
void get_and_process_gui_message();
void gui_thread()
{
while(!gui_shutdown_message_received())
{
get_and_process_gui_message();
std::packaged_task<void()> task;
{
std::lock_guard<std::mutex> lk(m_image);
if(tasks.empty())
continue;
task=std::move(tasks.front());
tasks.pop_front();
}
task(); //任务执行,执行完成后,期望 会被设置为就绪,可以取出一次
}
}
std::thread gui_bg_thread(gui_thread);
//将任务打包后,传给队列线程,返回期望的指针
template<typename Func>
std::future<void> post_task_for_gui_thread(Func f)
{
std::packaged_task<void()> task(f); //打包任务
std::future<void> res = task.get_future();
std::lock_guard<std::mutex> lk(m_image);
tasks.push_back(std::move(task));
return res;
}
//4.2.3使用std::promises
//上章中 包裹任务(包裹了整个函数,结果自动生成)--期望结果
//考虑一个线程处理多个连接事件,来自不同端口连接的数据包乱序方式进行处理
//数据包也将以乱序的方式进入队列
//一对std::promise/std::future 单线程处理多接口的实现
//promise只是包裹了返回值类型,需要自己set_value,或者set_exception设置结果
class data_packet
{
public:
int id;
};
class payload_type
{};
class connect_net{
private:
bool incoming;
bool outgoing;
std::string con_ip;
public:
connect_net(connect_net&&);
connect_net(std::string & s):con_ip(s),incoming(false),outgoing(false){};
void get_connect()
{
if(check_if_real_con())
incoming=true;
}
bool check_if_real_con()
{
return false;
}
void close_connect()
{
outgoing=false;
}
//
bool has_incoming_data()
{
return incoming;
};
bool has_outgoing_data()
{
return outgoing;
};
data_packet incoming_data()
{
return data_packet();
};
std::promise<payload_type> get_promise(int)
{
return std::promise<payload_type>();
};
};
class data_packet;
typedef std::vector<connect_net> connection_set;
bool done(connection_set&);
void process_connection(connection_set& connections)
{
while(!done(connections))
{
for(connection_set::iterator connection = connections.begin(),end =connections.end();
connection != end;
++connection)
{
if(connection->has_incoming_data())
{
data_packet data = connection->incoming_data();
auto p =connection->get_promise(data.id);
}
if(connection->has_outgoing_data())
{
}
}
}
};
//包裹任务会自动处理异常,future能存储返回值或者异常(掩盖住,调用的时候不抛出)
//为promise期望存储异常
struct _data
{
int32_t value;
};
_data data = { 0 };
int mainfuc()
{
std::promise<_data> data_promise; //创建一个承诺
std::future<_data> data_future = data_promise.get_future(); //得到这个承诺封装好的期望
std::thread prepare_data_thread([](std::promise<_data> &data_promise){
std::this_thread::sleep_for(std::chrono::seconds(2)); //模拟生产过程
try {
data_promise.set_value({ 1 }); //通过set_value()反馈结果
} catch (...) {
data_promise.set_exception(std::current_exception() );
//如果没法设置结果,那么需要手动设置异常
}
}, std::ref(data_promise));
std::thread process_data_thread([](std::future<_data> &data_future){
std::cout << data_future.get().value << std::endl; //通过get()获取结果
}, std::ref(data_future));
prepare_data_thread.join();
process_data_thread.join();
system("pause");
return 0;
}
//4.2.5多个线程的等待
//std::future 不是线程安全的,多个线程访问,只有第一个有结果,后面的可能会抛异常..其是移动的
std::shared_future<int> sfi; //这个是可拷贝的,
//4.3 心跳连接,超时等如何处理,限定时间等待
//4.3.1 时钟类包含:
//现在时间,时间类型,节拍,同时时钟节拍的分布判断时钟是否稳定
auto t_sys=std::chrono::system_clock::now(); //不稳定
auto t_steady=std::chrono::steady_clock::now();//稳定
//auto t_highresolution = std::chrono::high_resolution_clock;
//时钟周期 std::ratio<1,25>; 1/25一秒一个
//时间间隔
std::chrono::duration<short,std::ratio<60,1>> time1; //60秒为单位
std::chrono::duration<double,std::ratio<1,1000>> time2;//1ms为单位
std::chrono::nanoseconds time3;
std::chrono::duration<double,std::centi> time4(100);//10ms为单位
auto count = time4.count();
//显示转换,截断
std::chrono::milliseconds ms(54834);
std::chrono::seconds s = std::chrono::duration_cast<std::chrono::seconds>(ms);
int some_tesk(){return 100;};
void do_something_with(int i);
std::future<int> future_1 = std::async(some_tesk);
void test_fff(){
//wait_for,超时等待结果
if(future_1.wait_for(std::chrono::milliseconds(35)) == std::future_status::ready)
do_something_with(future_1.get());
}
//4.3.3时间点
void test_time_point(){
auto start = std::chrono::high_resolution_clock::now();
do_something_with(10);
auto stop =std::chrono::high_resolution_clock::now();
std::cout<<"do somethig time: "<<std::chrono::duration<double,std::chrono::seconds>(stop-start)<<"seconds"<<std::endl;
}
//超时等待一个条件变量(没有事件可等待的时候的),类似于定时器
std::condition_variable cv;
bool work_done;
std::mutex m;
bool wait_loop()
{
auto const timeout=std::chrono::system_clock::now()+std::chrono::microseconds(5000);
std::unique_lock<std::mutex> lk(m);
while(!work_done)
{
if(cv.wait_until(lk,timeout) == std::cv_status::timeout )
break;
}
return work_done;
}
//4.3.4具有超时功能的函数,wait_for(),wait_until()..
/*
std::this_thread
std::condition_variable;
std::condition_variable_any;
std::timed_mutex;
std::recursive_timed_mutex;
std::unique_lock<<#class _Mutex#>>;
std::future<<#class _Rp#>>;
std::shared_future<<#class _Rp#>>;
*/
//4.4实战
//4.12 快速排序--顺序实现版(非并行)
template <typename T>
std::list<T> sequential_quick_sort(std::list<T> input)
{
if(input.empty())
return input;
std::list<T> result;
//splice 插入算法(把后面框出来的元素,前插到指定迭代器)
//运行结果result 包含一个元素
result.splice(result.begin(),input,input.begin());
const T& pivot = *result.begin();
auto divide_point = std::partition(input.begin(), input.end(),
[&](const T& t){return t<pivot;});
std::list<T> lower_part;
lower_part.splice(lower_part.end(),input,input.begin(),divide_point);
auto new_lower(sequential_quick_sort(std::move(lower_part) ));
auto new_higher(sequential_quick_sort(std::move(input)));
result.splice(result.begin(),new_lower);
result.splice(result.end(),new_higher);
return result;
}
//4.13 快速排序--"期望"并行版,递归开辟线程,垃圾实现
template<typename T>
std::list<T> parallel_quick_sort(std::list<T> input)
{
if(input.empty())
return input;
std::list<T> result;
result.splice(result.begin(),input,input.begin());
const T& pivot = *result.begin();
auto divide_point = std::partition(input.begin(), input.end(),
[&](const T& t){return t<pivot;});
std::list<T> lower_part;
lower_part.splice(lower_part.end(),input,input.begin(),divide_point);
//开启一个线程,对小半边排序,
std::future<std::list<T>> new_lower
(std::async(¶llel_quick_sort<T>(),std::move(lower_part)));
auto new_higher(parallel_quick_sort(std::move(input)));
result.splice(result.begin(),new_lower.get());
result.splice(result.end(),new_higher);
return result;
}
//4.14 包裹 std::packaged_tast 与 std::thread
template<typename F,typename A> //内嵌类型必须typename显示表明
std::future<typename std::result_of<F(A&&)>::type > spawn_task(F&& f,A&& a)
{
typedef typename std::result_of<F(A&&)>::type result_type;
std::packaged_task<result_type(A&&)> task(std::move(f));
std::future<result_type> res(task.get_futury());
std::thread t(std::move(task),std::move(a));
return res;
}
//ATM逻辑类的简单实现
/*
struct card_inserted{
std::string account;
};
namespace messageing {
class receiver{
public:
std::condition_variable mes;
void receive(std::string &);
};
class sender{
public:
void send(std::string &);
};
}
std::string welcome("请插入银行卡!");
class atm{
messageing::receiver incoming;
messageing::sender bank;
messageing::sender interface_hard;
void (*state)();
std::string account;
std::string pin;
void waiting_for_card()
{
//
interface_hard.send(welcome);
incoming.wait()
}
};
*/
//第5章 底层内存模型与原子操作
//标准原子类型鼻祖
std::atomic_flag f_ato =ATOMIC_FLAG_INIT; //初始化为"清除"
//实现自旋互斥锁(阻塞测试锁)
class spinlock_mutex
{
std::atomic_flag flag;
public:
spinlock_mutex():flag(ATOMIC_FLAG_INIT){}
void lock()
{
//test and set 原子操作,阻塞式读取
while(flag.test_and_set(std::memory_order_acquire));
}
void unlock()
{
flag.clear(std::memory_order_release);
}
};
//atomic类型
void test_atomic_bool(){
std::atomic<bool> atomic_b(true);
atomic_b=false; //以上2句都是原子操作
//对原子变量的读,写,读改写
bool x=atomic_b.load(std::memory_order_acquire);
atomic_b.store(true);
x=atomic_b.exchange(false,std::memory_order_acq_rel);
}
//不同线程对数据的读写
std::vector<int> data_a;
std::atomic<bool> data_ready(false);
void reader_thread()
{
while(!data_ready.load())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
std::cout<<"the answer="<<data_a[0]<<"/n";
}
void writer_thread()
{
data_a.push_back(42);
data_ready=true;
}
//以上章节没看太懂
//第6章, 基于锁的并发数据结构设计
/*
1.锁的范围中的操作,是否在锁外能够执行?
2.数据结构中不同的区域是否被不同的互斥量保护?
3.所有操作都需要同级互斥量保护吗?
4.能否对数据结构进行简单的修改,提高并发效率?
总结:如何让序列化访问最小,让真实并发最大化
入门:基于互斥量和锁的并发数据结构设计 进阶:无锁并发数据结构设计 高端:原子操作大乱炖
*/
//线程安全的队列
template<typename T>
class threadsafe_queue_version1
{
private:
std::mutex mut;
std::queue<T> local_queue;
std::condition_variable data_cond;
public:
threadsafe_queue_version1();
threadsafe_queue_version1(const threadsafe_queue_version1&);
threadsafe_queue_version1& operator=(const threadsafe_queue_version1&) =delete;
void push(T& new_value)
{
std::lock_guard<std::mutex> lk(mut);
local_queue.push(new_value);
data_cond.notify_one();
};
//出队列,使用非条件变量出队列
bool try_pop(T& value);
std::shared_ptr<T> try_pop()
{
std::lock_guard<std::mutex> lk(mut);
if(local_queue.empty())
return std::shared_ptr<T>();
std::shared_ptr<T> res(std::make_shared<T>(local_queue.fornt()));
return res;
};
void wait_and_pop(T&value)
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk,[this]{return !local_queue.empty();});
value=local_queue.fornt();
local_queue.pop();
};
//返回只能指针版本,资源消耗稍微大一些
std::shared_ptr<T> wait_and_pop()
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk,[this]{return !local_queue.empty();});
std::shared_ptr<T> res(std::make_shared<T>(std::move(local_queue.front()))); //4
local_queue.pop();
return res;
};
bool empty() const
{
std::lock_guard<std::mutex> lk(mut);
return local_queue.empty();
};
};
//上面版本 4处构造函数可能会抛出异常,且pop线程可能开启后 没法关闭,将local_queue 结构改成 std::queue<shared_ptr<T>> 可以解决
//6.2.3使用细粒度锁,与 条件变量 实现高性能线程安全队列
//单线程队列
template <typename T>
class queue_one_thread
{
private:
struct node
{
T data;
std::unique_ptr<node> next;
node(T node_a): data(std::move(data_a)){}
};
std::unique_ptr<node> head;
node* tail;
public:
queue_one_thread(){};
queue_one_thread(const queue_one_thread&) = delete;
queue_one_thread& operator=(const queue_one_thread&) = delete ;
std::shared_ptr<T> try_pop()
{
//队列为空
if(!head)
{
return std::shared_ptr<T>();
}
//取出head的元素,制作成共享指针复制给res
const std::shared_ptr<T> res(std::make_shared<T>(head->data));
//为何不直接使用a=a->next
std::unique_ptr<node> const old_head=std::move(head);
head = std::move(old_head->next);
return res;
}
void push(T new_value)
{
//使用 new_value 构造 node ,再利用node 构造 p
std::unique_ptr<node> p(new node(std::move(new_value)));
node * const new_tail = p.get(); // unique.get() 返回指针
if(tail)
tail->next = std::move(p);
else
head =std::move(p);
tail = new_tail;
}
bool empty()
{
return !head;
}
};
/*分析:
1.头指针,尾指针 一般情况下指向的数据之间没关联(即,可以同时出头,进尾),唯一问题是,当只有一个元素的时候
2.当没有元素的时候, push要锁住尾,同时可能要操作头,因此可能要同时锁住头尾(2个锁,可能带来死锁问题)
*/
//6.6线程安全的队列 try_pop 和wait_pop 混合
template <typename T>
class threadsafe_queue_version2
{
private:
struct node
{
std::shared_ptr<T> data;
std::unique_ptr<node> next;
};
std::condition_variable head_cond;
std::mutex head_mutex;
std::unique_ptr<node> head;
std::mutex tail_mutex;
node* tail;
node* get_tail()
{
std::lock_guard<std::mutex> tail_lock(tail_mutex);
return tail;
}
//对尾加锁,判断是否为空 ,必须接在锁定头指针之后的代码中
bool is_empty()
{
return head.get()==get_tail();
}
std::unique_ptr<node> pop_head()
{
//返回头指针
std::unique_ptr<node> old_head(std::move(head));
head=std::move(old_head->next);
return old_head;
}
public:
threadsafe_queue_version2():head(new node),tail(head.get()){};
threadsafe_queue_version2(const threadsafe_queue_version2&) = delete;
threadsafe_queue_version2& operator=(const threadsafe_queue_version2&) = delete;
//从尾部推入数据,只需要锁住尾部
void push(T new_value)
{
//下面3句话可能会抛出异常,但是这里面使用的智能指针,所以 结果只是没有push运行,是异常安全的
std::shared_ptr<T> new_data(std::make_shared<T>(std::move(new_value)));
std::unique_ptr<node> p(new node); //新尾节点
node* new_tail=p.get();
std::lock_guard<std::mutex> lock_tail(tail_mutex);
tail->data = new_data;
tail->next = std::move(p);
tail=new_tail;
//通知有数据了
head_cond.notify_one();
}
//尝试弹出,无数据弹出空指针
std::shared_ptr<T> try_pop()
{
std::unique_ptr<node> res;
std::lock_guard<std::mutex> head_lock(head_mutex);
//不为空的时候 此处先获取 头锁,再获取 尾锁 (程序不存在其他的地方先获取尾锁,再获取头锁,所以不会死锁)
if(!is_empty())
{
res=std::move(pop_head());//对锁的操作会产生异常,这里对数据的操作都是 在获取全部锁之后,所以是异常安全的
return res->data;
}
else
return std::shared_ptr<T>();
};
//返回智能指针版本,资源消耗稍微大一些
std::shared_ptr<T> wait_and_pop(){
std::unique_lock<std::mutex> lk(head_mutex);
head_cond.wait(lk, [this]{return !is_empty();}); //等待不为空,那么必然能pop出头了
//返回头指针
std::unique_ptr<node> old_head(std::move(head));
head=std::move(old_head->next);
return old_head->data;
}
//是否为空
bool empty(){
std::lock_guard<std::mutex> head_lock(head_mutex);
return is_empty();
}
};
//6.3基于锁设计更加复杂的数据结构
//支持并发的map
/*
存在的问题:
1.要访问的迭代器被其他线程删除
2.添加数据后,遍历顺序的影响
思考:不返回引用,用一个互斥锁对每个函数上锁,并行还存在吗?
即使使用读写锁,同时也只有一个线程能修改map,如何提高性能?
基本数据结构: 二叉树(红黑树),有序数组,哈希表
分析:二叉树,根节点向下查找,每次需要锁住当前节点,同时锁可以向下传递,越上层锁住的面积越大嘛,放弃
有序数组,不解释
哈希表,假设有N个桶,那么每个桶都自带一个锁,可能能提高N倍性能
*/
//6.11 线程安全的查询表
template <typename Key,typename Value,typename Hash=std::hash<Key>>
class threadsafe_lookup_table
{
private:
//包裹好,数据为(key,value)的链表
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 boost::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:
//找到Key的对应的值,使用读锁
Value value_for(Key const& key,Value const& default_value) const
{
boost::shared_lock<boost::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<boost::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<boost::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; //hash函数,
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];//此处为何要reset啊?
}
threadsafe_lookup_table(const threadsafe_lookup_table&) = delete;
threadsafe_lookup_table& operator=(const threadsafe_lookup_table&) = 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_updata_mapping(Key const& key,Value const& value)
{
get_bucket(key).add_or_updata_mapping(key,value);
}
void remove_mapping(Key const& key)
{
get_bucket(key).remove_mapping(key);
}
};
//6.3.2编写线程安全的队列
/////////////第七章,无锁并发数据结构设计
//第8章并发代码设计
/*
线程间划分数据技术,影响并发性能的因素,数据结构设计对性能的影响
多线程中的异常安全,可扩展性,并行算法的实现
*/
//8.1 如何在线程间划分工作
//////////////8.1.2基于数据的划分
//1.事先划分
//2.递归划分,快排(线程数指数级生成,销毁)
//3.使用栈的并行快速排序算法---等待数据库排序
template <typename T>
struct sorter
{
//待排序的块
struct chunk_to_sort
{
std::list<T> data;
std::promise< std::list<T> > promise;
};
//线程安全的栈,节点是 待排序的块
threadsafe_stack<chunk_to_sort> chunks;
std::vector<std::thread> threads;
unsigned const max_thread_count;
std::atomic<bool> end_of_data;
sorter():max_thread_count(std::thread::hardware_concurrency() - 1),
end_of_data(false){}
~sorter()
{
end_of_data = true;
//等线程结束后,再析构
for(unsigned i =0;i<threads.size();++i)
threads[i].joni();
}
//线程开启入口
void sort_thread()
{
while(!end_of_data)
{
try_sort_chunk();
std::this_thread::yield();
}
}
//从栈中弹出,排序
void try_sort_chunk()
{
boost::shared_ptr<chunk_to_sort> chunk = chunks.pop();
if(chunk)
{
sort_chunk(chunk);
}
}
void sort_chunk(boost::shared_ptr<chunk_to_sort> const & chunk )
{
chunk->promise.set_value(do_sort(chunk->data));
}
std::list<T> do_sort(std::list<T>& chunk_data)
{
if(chunk_data.empty())
return chunk_data;
std::list<T> result;
result.splice(result.begin(),chunk_data,chunk_data.begin());
T const& partition_val =*result.begin();
typename std::list<T>::iterator divide_point =
std::partition(chunk_data.begin(),chunk_data.end(),
[&](T const& val){return val < partition_val;});
//左半边
chunk_to_sort new_lower_chunk;
new_lower_chunk.data.splice(new_lower_chunk.data.end(),chunk_data,chunk_data.begin(),divide_point);
//拿到左边块排序期望,将任务丢进栈
std::future<std::list<T>> new_lower = new_lower_chunk.promise.get_future();
chunks.push(std::move(new_lower_chunk));
if(threads.size() < max_thread_count)
{
threads.push_back(std::thread(&sorter<T>::sort_thread,this));
}
std::list<T> new_higher(do_sort(chunk_data));
result.splice(result.ends(),new_higher);
//当没有数据需要在等待排序的时候,此语句 轮询,性能有影响
//wait_for() 不会阻塞,get()会阻塞
while(new_lower.wait_for(std::chrono::seconds(0)) != std::future_status::ready )
{
try_sort_chunk();
}
result.splice(result.begin(),new_lower.get());
return result;
}
};
template <typename T>
std::list<T> parallel_quick_sort_thread_auto(std::list<T> input)
{
if(input.empty())
return std::move(input);
sorter<T> s;
return s.do_sort(input);
}
///////8.1.3通过任务类型划分工作
//分离工种,然工种间密切的交互,当所有交互都关于同样的问题时候,可以将工种合并
//划分任务序列,get数据流水线,对数据分块,并发
//8.2影响并发代码性能的因素
//8.2.1 cpu数量带来的问题
//8.2.2乒乓缓存
//处理器,每个处理器独立缓存,处理器会等待更新缓存(高竞争)
std::atomic<unsigned long> counter(0);
void process_loop()
{
//乒乓缓存
//相互等待,性能影响大, 当cpu等待缓存的时候,不能做任何事情..
while(counter.fetch_add(1,std::memory_order_relaxed)< 10000000 )
{
do_something(1);
}
}
//8.2.3 伪共享
//线程之间访问的数据过于接近
//比如2个int在内存中相邻, 大家虽然互斥的不是同一个变量,但是互斥的是同一个内存行(32,64B)
//8.2.4让内存数据紧凑
//减少两个线程对同一个内存位置的竞争,避免乒乓缓存
//将线程自己访问的内存放在一起, 将共享内存,每个并发 隔开放
//当线程数量少的时候,又会带来(不使用空间,时间性),导致缺页中断发生
//8.2.5超额认购与频繁的任务切换
//考虑开始最写的并发排序,5层递归32个线程..
/////8.3 为多线程性能设计的 数据结构
//8.3.1 为复杂操作 划分数组元素
//考虑大矩阵相乘 C=B*A的时候
//8.3.2其他数据结构中的数据访问模式
/*
1.尝试调整数据在线程间分布,让同一线线程数据紧凑
2.减少线程需要的数据量
3.不同线程访问不同位置,避免伪共享
*/
class data_item1
{};
class data_item2
{};
//测试伪共享
struct my_data_test{
data_item1 d1;
data_item2 d2;
char padding[65536];
};
//测试互斥量
struct protected_data
{
std::mutex m;
char padding[65536];// 超过缓存行的大小
my_data_test data_to_protect;
};
//异常安全,可扩展性
//8.4.3使用多线程隐藏延时
//多线程病毒扫描
//在线程等待事件阻塞的时候,充分分配其他任务,比如多线程快排
//8.4.4使用并发提高响应能力
//将GUI线程与任务线程分离
std::thread task_thread;
std::atomic<bool> task_cancelled(false);
enum eventType
{
start_task,
stop_task,
task_complete,
quit
};
class event_data
{
public:
eventType type;
};
//并发事件队列
threadsafe_queue<event_data> work_event;
void task()
{
/*
while(!task_complete() && ! task_cancelled)
{
do_next_operation();
}
if(task_cancelled )
{
perform_clearup();
}
else{
//传给事件队列
post_gui_event(task_completa);
}
*/
}
void process(event_data const& event)
{
switch(event.type)
{
case start_task:
task_cancelled=false;
task_thread= std::thread(task);
break;
case stop_task:
task_cancelled = true;
task_thread.join();
break;
case task_complete:
task_thread.join();
//display_result();
break;
default:
break;
//...
}
}
//gui线程
event_data get_event();
void gui_thread_along()
{
while(true)
{
//获取事件,鼠标点击,阻塞式
event_data event =get_event();
if(event.type == quit)
break;
process(event);
}
}
//8.5一些并行设计代码
//并行实现std::for_each
/*
对任务划分,如果想保存线程中的异常,可以使用std::package_task,asycn机制
*/
class join_threads
{
private:
std::vector<std::thread> j_threads;
public:
join_threads(std::vector<std::thread>& th ):j_threads(std::move(th)){};
~join_threads()
{
for(unsigned long i=0;i < j_threads.size();++i)
{
if(j_threads[i].joinable())
j_threads[i].join();
}
}
};
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_thread = (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 ? 2:hardware_threads, max_thread);
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;
Iterator block_end =block_start;
for(unsigned long i=0;i<(num_threads-1);++i)
{
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();
}
}
//并行find算法实现
template <typename Iterator ,typename MatchType>
Iterator parallel_find(Iterator first,Iterator last,MatchType match)
{
struct find_element
{
void operator()(Iterator begin,Iterator end,MatchType match,std::promise<Iterator>* result,std::atomic<bool>* done_flag)
{
try
{
for(;begin!=end && !done_flag->load();++begin)
{
if(*begin == match)
{
//设置找到的位置,同时标记原子变量 ,此处存在竞争,但是 第一个元素会设置为promise
result->set_value(begin);
done_flag->store(true);
return ;
}
}
}
catch(...)
{
try {
result->set_exception(std::current_exception());
done_flag->store(true);
} catch (...) {
}
}
}
};
unsigned long const length = std::distance(first, last);
if(!length)
return ;
unsigned long const min_per_thread =25;
unsigned long const max_thread = (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 ? 2:hardware_threads, max_thread);
unsigned long const block_size = length/num_threads;
std::promise<Iterator> result;
std::atomic<bool> done_flag(false);
std::vector<std::thread> threads(num_threads-1);
{
//线程包裹
join_threads joiner(threads);
Iterator block_start=first;
Iterator block_end =block_start;
for(unsigned long i=0;i<(num_threads-1);++i)
{
block_end =block_start;
std::advance(block_end, block_size);
threads[i]=std::thread(find_element(),block_start,block_end,&result,&done_flag);
block_start = block_end;
}
find_element(block_start,last,&result,&done_flag);
if(!done_flag.load())
{
return last;
}
return result.get_guture().get();
}
};
//高级 std::partial_sum 并发代码实现,留作练习
//第9章 高级线程管理
//9.1.1最简单的线程池
class thread_pool
{
std::atomic_bool done;
//std::function<T> ,T只支持能拷贝的类型 //此线程池处理的任务是无参数,无返回的任务
threadsafe_queue_version2<std::function<void()>> work_queue;
std::vector<std::thread> threads;
join_threads joiner; //
void worker_thread()
{
while(!done) //还有工作
{
std::shared_ptr<std::function<void()>> task_p(work_queue.try_pop());
if(task_p==nullptr)
{
std::this_thread::yield(); //放弃CPU时间片,加入抢占队列
}
else
{
std::function<void()> task= *task_p;
task(); //工作
}
}
}
public:
thread_pool():done(false),joiner(threads)
{
unsigned const thread_count = std::thread::hardware_concurrency()-1;
try{
for(unsigned int i=0 ;i <thread_count ;++i)
{
//初始化线程池,让所有线程进入循环工作状态
threads.push_back(std::thread(&thread_pool::worker_thread,this));
}
}
catch(...)
{
done=true;
throw;
}
}
~thread_pool()
{
done=true;
}
template<typename FunctionType>
void submit(FunctionType f)
{
work_queue.push(std::function<void()>(f));
}
};
//主线程 等待提交到线程池中的任务结果, 汇总
/*
submit返回任务句柄
//std::function<std::packaged_task<void()>> ftc; 失败,类型不支持拷贝
*/
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:
//模板构造函数,以F类型,来构造
template <typename F>
function_wrapper(F&&f):impl(new impl_type<F>(std::move(f))){};
//仿函数功能
void operator()(){impl->call();};
function_wrapper()= default;
//移动构造
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& other) = delete;
function_wrapper(function_wrapper &) =delete;
function_wrapper& operator=(function_wrapper& other) = delete;
};
//线程开启池,线程任务随着池子析构
class thread_pool_2
{
std::atomic_bool done;
//std::function<T> ,T只支持能拷贝的类型 //此线程池处理的任务是无参数,无返回的任务
threadsafe_queue_version2<function_wrapper> work_queue;
std::vector<std::thread> threads;
join_threads joiner; //
void worker_thread()
{
//开辟的线程循环检测是否有工作,线程池析构的时候才退出线程,性能影响较大
while(!done)
{
auto task_p=work_queue.try_pop();
if(task_p==nullptr)
{
std::this_thread::yield(); //放弃CPU时间片,加入抢占队列
}
else
{
function_wrapper task(std::move(*task_p));
task(); //工作
}
}
}
public:
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(std::move(task));
return res;
}
thread_pool_2():done(false),joiner(threads)
{
unsigned const thread_count = std::thread::hardware_concurrency();
try{
for(unsigned int i=0 ;i <thread_count ;++i)
{
//初始化线程池,让所有线程进入循环工作状态
threads.push_back(std::thread(&thread_pool_2::worker_thread,this));
}
}
catch(...)
{
done=true;
throw;
}
}
~thread_pool_2()
{
done=true;
}
};
//使用
//多线程求和,不带异常处理
template<typename Iterator,typename T>
T parallel_accumulate_thread_poll(Iterator first,Iterator last,T init)
{
unsigned long const length =std::distance(first, last);
if(!length)
return init;
//每个任务分配的数量
unsigned long const block_size = 25;
unsigned long const num_blocks=(length+block_size-1)/block_size;
std::vector<std::future<T>> futures(num_blocks);
thread_pool_2 pool;
Iterator block_start =first;
Iterator block_end =block_start;
for(unsigned long i=0;i<num_blocks-1;++i)
{
block_end =block_start;
std::advance(block_end, block_size);
futures[i]=pool.submit(
[block_start,block_end,init]()->T{
T result=init-init;
T last_resu =accumulate_block<Iterator, T>()(block_start,block_end,result);
return last_resu;
}
);
block_start=block_end;
}
T last_resu=init-init;
T last_result=accumulate_block<Iterator,T>()(block_start,last,last_resu);
T result=init;
T t_lin;
for(unsigned long i =0;i <num_blocks-1 ;++i)
{
t_lin=futures[i].get();
//std::cout<<t_lin<<std::endl;
result += t_lin;
}
result+=last_result;
return result;
};
//////等待 依赖于任务,可管理线程的池子
class thread_pool_3
{
std::atomic_bool done;
//std::function<T> ,T只支持能拷贝的类型 //此线程池处理的任务是无参数,无返回的任务
threadsafe_queue_version2<function_wrapper> work_queue;
std::vector<std::thread> threads;
join_threads joiner; //
void worker_thread()
{
//开辟的线程循环检测是否有工作,线程池析构的时候才退出线程,性能影响较大
while(!done)
{
auto task_p=work_queue.try_pop();
if(task_p==nullptr)
{
std::this_thread::yield(); //放弃CPU时间片,加入抢占队列
}
else
{
function_wrapper task(std::move(*task_p));
task(); //工作
}
}
}
public:
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(std::move(task));
return res;
}
thread_pool_3():done(false),joiner(threads)
{
unsigned const thread_count = std::thread::hardware_concurrency();
try{
for(unsigned int i=0 ;i <thread_count ;++i)
{
//初始化线程池,让所有线程进入循环工作状态
threads.push_back(std::thread(&thread_pool_3::worker_thread,this));
}
}
catch(...)
{
done=true;
throw;
}
}
~thread_pool_3()
{
done=true;
}
/////////////运行分配的任务接口
void run_pending_task()
{
auto task_p=work_queue.try_pop();
if(task_p==nullptr)
{
std::this_thread::yield(); //放弃CPU时间片,加入抢占队列
}
else
{
function_wrapper task(std::move(*task_p));
task(); //工作
}
}
};
//基于任务管理的线程池 快排
template <typename T>
struct sorter_pool
{
thread_pool_3 pool;
std::list<T> do_sort(std::list<T>& chunk_data)
{
if(chunk_data.empty())
return chunk_data;
std::list<T> result;
result.splice(result.begin(),chunk_data,chunk_data.begin());
T const& partition_val =*result.begin();
typename std::list<T>::iterator divide_point =
std::partition(chunk_data.begin(),chunk_data.end(),
[&](T const& val){return val < partition_val;});
//左半边
std::list<T> new_lower_chunk;
new_lower_chunk.data.splice(new_lower_chunk.data.end(),chunk_data,chunk_data.begin(),divide_point);
//拿到左边块排序期望,将任务丢进栈
std::future<std::list<T>> new_lower = pool.submit(std::bind(&sorter_pool::do_sort,this,std::move(new_lower_chunk)));
std::list<T> new_higher(do_sort(chunk_data));
result.splice(result.ends(),new_higher);
//当没有数据需要在等待排序的时候,此语句 轮询,性能有影响
while(new_lower.wait_for(std::chrono::seconds(0)) != std::future_status::ready )
{
pool.run_pending_task();
}
result.splice(result.begin(),new_lower.get());
return result;
}
};
///任务队列分开的线程池
class thread_pool_queue
{
std::atomic_bool done;
//std::function<T> ,T只支持能拷贝的类型
//此线程池处理的任务是无参数,无返回的任务
//全局工作队列
threadsafe_queue_version2<function_wrapper> pool_work_queue;
typedef std::queue<function_wrapper> local_queue_type;
//定义线程自己的工作队列
static thread_local std::unique_ptr<local_queue_type> local_work_queue;
std::vector<std::thread> threads;
join_threads joiner; //
void worker_thread()
{
//初始化线程工作队列
local_work_queue.reset(new local_queue_type);
//检测线程池是否结束
while(!done)
{
run_pending_task();
}
}
public:
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());
//自己有任务队列
if(local_work_queue)
{
local_work_queue->push(std::move(task));
}
else
{
pool_work_queue.push(std::move(task));
}
return res;
}
thread_pool_queue():done(false),joiner(threads)
{
unsigned const thread_count = std::thread::hardware_concurrency();
try{
for(unsigned int i=0 ;i <thread_count ;++i)
{
//初始化线程池,让所有线程进入循环工作状态
threads.push_back(std::thread(&thread_pool_queue::worker_thread,this));
}
}
catch(...)
{
done=true;
throw;
}
}
~thread_pool_queue()
{
done=true;
}
/////////////运行分配的任务接口
void run_pending_task()
{
//自己有任务队列
if(local_work_queue && !local_work_queue->empty())
{
function_wrapper task;
task = std::move(local_work_queue->front());
local_work_queue->pop();
task();
}
else
{
auto task_p =pool_work_queue.try_pop();
if(task_p==nullptr)
{
std::this_thread::yield(); //放弃CPU时间片,加入抢占队列
}
else
{
function_wrapper task;
task=(std::move(*task_p));
task(); //工作
}
}
}
};
////////窃取任务线程池
//队列中实现一个try_steal对外接口
/////包裹实现一个 可中断线程
class interrupt_flag
{
public:
void set();
bool is_set() const;
};
// 命名空间线程本地变量,当线程启动时,如果入口处于该命名空间中,就会实例化这个变量
thread_local interrupt_flag this_thread_interrupt_flag;
class interruptible_thread
{
private:
interrupt_flag* flag;
std::thread internal_thread;
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();
}
}
};
template <typename ReturnType ,typename ...Args>
class test_mutux
{
public :
};
C++并发编程学习笔记的更多相关文章
- Java并发编程学习笔记
Java编程思想,并发编程学习笔记. 一.基本的线程机制 1.定义任务:Runnable接口 线程可以驱动任务,因此需要一种描述任务的方式,这可以由Runnable接口来提供.要想定义任务,只需实现R ...
- 并发编程学习笔记(15)----Executor框架的使用
Executor执行已提交的 Runnable 任务的对象.此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节.调度等)分离开来的方法.通常使用 Executor 而不是显式地创建 ...
- 并发编程学习笔记(14)----ThreadPoolExecutor(线程池)的使用及原理
1. 概述 1.1 什么是线程池 与jdbc连接池类似,在创建线程池或销毁线程时,会消耗大量的系统资源,因此在java中提出了线程池的概念,预先创建好固定数量的线程,当有任务需要线程去执行时,不用再去 ...
- 并发编程学习笔记(13)----ConcurrentLinkedQueue(非阻塞队列)和BlockingQueue(阻塞队列)原理
· 在并发编程中,我们有时候会需要使用到线程安全的队列,而在Java中如果我们需要实现队列可以有两种方式,一种是阻塞式队列.另一种是非阻塞式的队列,阻塞式队列采用锁来实现,而非阻塞式队列则是采用cas ...
- 并发编程学习笔记(11)----FutureTask的使用及实现
1. Future的使用 Future模式解决的问题是.在实际的运用场景中,可能某一个任务执行起来非常耗时,如果我们线程一直等着该任务执行完成再去执行其他的代码,就会损耗很大的性能,而Future接口 ...
- 并发编程学习笔记(12)----Fork/Join框架
1. Fork/Join 的概念 Fork指的是将系统进程分成多个执行分支(线程),Join即是等待,当fork()方法创建了多个线程之后,需要等待这些分支执行完毕之后,才能得到最终的结果,因此joi ...
- 并发编程学习笔记(10)----并发工具类CyclicBarrier、Semaphore和Exchanger类的使用和原理
在jdk中,为并发编程提供了CyclicBarrier(栅栏),CountDownLatch(闭锁),Semaphore(信号量),Exchanger(数据交换)等工具类,我们在前面的学习中已经学习并 ...
- 并发编程学习笔记(9)----AQS的共享模式源码分析及CountDownLatch使用及原理
1. AQS共享模式 前面已经说过了AQS的原理及独享模式的源码分析,今天就来学习共享模式下的AQS的几个接口的源码. 首先还是从顶级接口acquireShared()方法入手: public fin ...
- 并发编程学习笔记(8)----ThreadLocal的使用及源码分析
1. ThreadLocal的理解 ThreadLocal,顾名思义,就是线程的本地变量,ThreadLocal会为每个线程创建一个本地变量副本,使得使用ThreadLocal管理的变量在多线程的环境 ...
- 并发编程学习笔记(6)----公平锁和ReentrantReadWriteLock使用及原理
(一)公平锁 1.什么是公平锁? 公平锁指的是在某个线程释放锁之后,等待的线程获取锁的策略是以请求获取锁的时间为标准的,即使先请求获取锁的线程先拿到锁. 2.在java中的实现? 在java的并发包中 ...
随机推荐
- ActiveMQ (二)—发布订阅模式
ActiveMQ的另一种模式就SUB/HUB即发布订阅模式,是SUB/hub就是一拖N的USB分线器的意思.意思就是一个来源分到N个出口.还是上节的例子,当一个订单产生后,后台N个系统需要联动,但有一 ...
- Python之print()函数
1. 输出字符串 >>> str = 'Hello World' >>> print (str) Hello World 2. 格式化输出整数 支持参数格式化 &g ...
- homework 张一刚
#include<stdio.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h& ...
- Winform 窗体实现圆角展示
触发窗体的Resize事件,如下所示: #region 界面实现圆角 private void LoginForm_Resize(object sender, EventArgs e) { if (t ...
- declaration may not appear after executable statement in block
keil 编译时出现 declaration may not appear after executable statement in block,找到keil工程对应的函数 定义的地方出现在了赋值的 ...
- Struts2多文件上传原理和示例
一.创建上传文件的页面,代码如下所示 1.Struts2也可以很方便地实现多文件上传. 在输入表单域增加多个文件域:multifileupload.jsp <%@ page lan ...
- 前端-JavaScript2-5——JavaScript之运算符进阶
运算符(Operators,也翻译为操作符),是发起运算的最简单形式. 运算符的分类见仁见智,我们的课程对运算符进行如下分类: 数学运算符(Arithmetic operators) 比较运算符(Co ...
- Ubuntu平台rm误删的文件如何恢复
安装:Ubuntu下也可以直接用apt-get来获取extundelete 以我自己的Ubuntu14.04.3来看: df 命令是linux系统上以磁盘分区为单位来查看文件系统的命令,后面可以加上不 ...
- numpy和matploptlib
numpy Numpy介绍 编辑 一个用python实现的科学计算,包括:1.一个强大的N维数组对象Array:2.比较成熟的(广播)函数库:3.用于整合C/C++和Fortran代码的工具包:4.实 ...
- php中获取当前时间
因为php种有时区的设置,默认与我们这边差8小时:所以我们直接使用data方法的话,得到的时间是不准确的 所以我们在开头设置时区 //设置时区的方法: date_default_timezone_se ...