您的位置:首页 > 编程语言 > C语言/C++

boost::thread

2016-09-23 08:32 316 查看
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);//等待100ms
if(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(d
d5fc
ummy,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其更关心函数的计算结果而不是过程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  boost c语言 线程