boost::thread

来源:互联网 发布:光盘菜单制作软件 编辑:程序博客网 时间:2024/04/29 18:24
thread
thread库需要chrono库提供时间概念来执行睡眠、等该操作。因此必须先编译chrono库
一、
mutex(互斥量):可以在多线程环境里面防止多线程同时操作共享资源。
thread提供了6种互斥量:
null_mutex:无任何锁定功能的互斥量
mutex:独占式互斥量,最简单实用。
timed_mutex:独占式互斥量,提供超时锁定功能。
recursive_mutex:递归式互斥量,可以多次锁定,同时需要多次解锁。
recursive_timed_mutex:
shared_mutex:C++14,读写锁
这些互斥量除了功能不同外基本接口都比较接近。
mutex用法:
boost::mutex mu;try{mu.lock();//用于线程阻塞等待直到获取互斥量的所有权//操作共享资源mu.unlock();}catch (){mu.unlock();}

注:使用try catch 以防异常发生,未调用unlocks
timed_mutex用法:
boost::timed_mutex mu;//定时互斥量auto flag = mu.try_lock_for(100_ms);//等待100msif(flag)//检查是否成功解锁互斥量{cout << "lock mutex"<<endl;mu.unlock();}...//未能解锁,执行其他操作


二、lock_guard(RAII)
辅助锁定互斥量,构造时候锁定互斥量,解析时候自动解锁,不可拷贝
mutex mu;
lock_guard<mutex> g(mu);//第一种构造形式
//执行操作
timed_mutex mu;if(mu.try_lock_for(100ms)){lock_guard<time_mutex> g(mu,adopt_lock);//第二种构造形式,认为线程之前已经锁定mutex,不会再执行锁定,但是会解锁。//访问共享资源}
unique_lock
注:工作机制和guard_lock相同,但是更加复杂,构造函数还可以接受其他的锁定选项,从而有不同的行为。
thread库中三个锁定选项:
struct defer_lock_t{};
struct try_to_lock_t{};
struct adopt_lock_t{};
在unique_lock构造函数里面使用这些标志常量就可以使得unique_lock产生不同的效果:
defer_lock: is_locked =false,不执行锁定功能
try_to_lock: is_locked=false,执行try_lock;
adopt_lock: is_locked=true,不执行锁定功能
工厂函数:
注:因为unique_lock支持转移语义,所以它可以从工厂函数产生。关于转移语义,工厂函数后面再谈。
mutex mu,mu1,mu2;{auto g = make_unique_lock(mu);//工厂函数锁定互斥量assert(g.owns_lock());//断言已经锁定//执行操作}{auto g = make_unique_lock(mu, defer_lock);//暂时不锁定互斥量assert(!g);assert(g.try_lock());//尝试锁定assert(g);//执行操作}//thread没有提供时间限定形式的工厂函数,实现自己的重载形式template <typename Lockable,typename D>unique_lock<Lockable> my_make_lock(Lockable& mtx, D d){return unique_lock<Lockable>(mtx, d);}timed_mutex tm;auto g = make_unique_locks(mu, tm);
lock适配器:
lock_guard和unique_lock大多数情况下和mutex搭配使用,用于锁定互斥量。但是他们是模板类,所以只要符合lockable概念,也就是有lock/unlock/try_lock接口的类都可以用于lock_guard和unique_lock。
thread定义的lockable适配器:
basic_lockable_adapter;
lockable_adapter;
timed_lockable_adapter;
例如:
class account final:public lockable_adapter<mutex>
{
}//该类继承于public lockable_adapter<mutex>,自动获得lock接口,因此接下来可讲account类用于unique_lock或者lock_guard。
account a; //account实例,可锁定
auto g = make_unique_lock(a); //无需其他mutex,自身可锁定
或者:
auto = make_unique_lock(a,try_to_lock);

lock函数:
除了使用mutex成员函数、LOck_guard/unique_lock,还可以使用自由函数lock()和try_lock(),类似与make_unique_locks(),可以一次性锁定多个互斥量,并且保证不出现锁死。
但是其没有推出作用域自动解锁的特性,但是保证发生异常就会解除对互斥量的锁定。
可以先使用make_unique_lock()的adopt_lock或者defer_lock锁定选项,但是暂时不锁定互斥量,然后用lock()或者try_lock()一次性锁定,退出时自动解锁。
mutex m1;
auto g1 = make_unique_lock(m1,adopt_lock);
lock(m1);

p:
1>------ 已启动生成: 项目: test_thread, 配置: Debug x64 ------
1> test_thread.cpp
1>D:\programing\boost_1_61_0\boost/type_traits/common_type.hpp(43): fatal error C1001: 编译器中发生内部错误。
1> (编译器文件“msc1.cpp”,第 1325 行)
1> 要解决此问题,请尝试简化或更改上面所列位置附近的程序。
1> 请选择 Visual C++
1> “帮助”菜单上的“技术支持”命令,或打开技术支持帮助文件来获得详细信息。
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========

thread:
实现了操作系统里的线程表示,负责启动和管理线程对象。
thread对象不可拷贝不可比较,但支持move,有转移构造函数和转移赋值函数,所以允许从工厂函数产生。
thread t1,t2;
cout << t1.get_id()<<endl;
assert(t1.get_id()==t2.get_id());//比较两个线程对象,但不符合c++标准hardware_concurrency()可以获得系统可以并发的线程数量。
physical_concurrency可以获得物理cpu核心数量。
自由函数boost::this_thread::get_id()/yield()/sleep_for()/sleep_until() 无需使用thread对象就可以操作当前线程。
线程执行流程:
1.当创建thread对象后,线程就立即执行
void dummy(int n){for(int i =0; i < n ; i ++)cout << n<<endl;}调用:int main(){thread t1(dummy,100);thread t2(dummy,300);this_thread::sleep_for(200_ms);//等待线程结束,否者会因为main()函数结束时线程对象的析构导致线程的强制终止。}
2.等待线程结束
thread成员函数joinable()可以用一个来判断thread对象是否标注了一个可执行的线程体。
join等待线程:
join():一直等待直到线程结束
try_join_for()/try_join_until():阻塞线程一定时间段,最后不管线程是否结束都结束返回。如果线程在时间段内结束,则直接返回。
thread t1(bind(dummy,100));//使用bind表达式启动线程
thread t2([]{dummy(500);});//使用lambda启动线程
t1.try_join_for(100ms);
t2.join();

detach分离线程:
成员函数detach()将thread与线程执行体手动分离,此后thread对象不代表任何线程体,joinable==0,此时线程仍将不受影响地继续执行,直到函数结束,或者跟随主进程一起结束。
#include<iostream>using namespace std;#include<boost/thread.hpp>#include<boost/thread/thread_guard.hpp>void dummy(int n){for (int i = 0; i < n; i++)cout << n << endl;}int main(){boost::thread t1(dummy, 500);boost::thread t2(dummy, 1000);cout << t1.joinable() << endl;t1.detach();//与线程执行体分离cout << t1.joinable() << endl;boost::thread_guard<>g2(t2);//析构时等待线程结束}
中断线程
interrupt(),interruption_requested();
注:线程并不是在任何时候都能中断,只有当线程执行到中断点的时候才能被中断。
线程末仍情况下都是允许被中断的,thread库允许进一步控制线程的中断行为。
interruption_enable()//检测当前函数是否允许中断
interruption——requested//检测当前线程是否被要求中断

thread_group
用于管理一组线程,内部使用std::list<thread*>来容纳创建的thread对象
成员函数create_thread()是一个工厂函数,可以创建thread对象并且运行程序,同时加入内部list。但是不支持如thread构造函数那样传递函数参数的用法,所以用bind或者lambda来包装执行的函数。
void dummy(int x){for (int i = 0; i < x; i++)cout << x << endl;}int main(){thread_group tg;tg.create_thread(bind(dummy, 200));tg.join_all();//等待所有线程执行结束}


call_once
在多线程调用函数时候只能有一个线程调用成功
 int g_count;//全局变量,目标:一次初始化void init_count(int x){cout << "should call once." << endl;g_count = x;}void call_func(){static once_flag two;//一次初始化标志,调用call_once()必须先申明once_flag对象,而不能用临时变量call_once(two, init_count, 10);}int main(){thread_group tg;tg.create_thread(bind(call_func));tg.create_thread(bind(call_func));tg.join_all();}
条件变量
另一种用于等待的机制,可以实现进程之间通信,必须和互斥量配合使用,等待另一个线程中某个事情发生
thread库提供两种条件变量对象:
condition_Variable
condition_Variable_any//能够适应更广泛的互斥量类型。

shared_mutex
允许线程获取倒戈 共享所有权和一个专享所有权,即可以实现多个读线程一个写线程。

feature:
异步操作线程返回值的方法。
函数async()函数用于产生feature对象,异步启动一个线程运行函数,返回feature对象,随后就可以利用feature获取计算结果。
相比于thread其更关心函数的计算结果而不是过程。

0 0
原创粉丝点击