并发低层接口:thread和promise

thread

thread是C++11引入的一个处理并发的低层接口。

1、操作
操作作用
thread t默认构造函数,创建一个没有关联线程(nonjoinable)的thread对象
thread t(f, …)创建一个关联到线程(joinable)的thread对象。这是一个可变参模板函数,f 是线程函数,f后面的函数参数是f的传参;或抛出std::system_error
thread t(rv)移动构造函数,取rv的状态并使rv变成nonjoinable
~thread()析构函数,如果thread对象是joinable,则调用std::terminate()
t = rv移动赋值运算符,如果rv是joinable则调用std::terminate()
t.joinable()判断thread对象是否关联到线程
t.join()等待关联线程完成工作,然后使t变成nonjoinable。如果t不是joinable则抛出std::system_error
t.detach()让线程在后台运行,并使t变成nonjoinable。如果t不是joinable则抛出std::system_error
t.get_id()如果t是joinable,则返回一个唯一的thread id;否则返回std::thread::id()
2、细节1

线程函数如果发生异常并未被捕获,程序会被终止并调用std::terminate()。

3、细节2

对于joinable thread,必须调用join()或detach(),或者通过移动构造、移动赋值使它成为nonjoinable,否则在thread对象生命期结束时程序会终止并调用std::terminate()。需要注意的是,在创建一个关联到线程的thread对象时线程就开始执行,而不是调用join或detach时才执行。

4、关于detached thread

需要注意的是,调用detach()运行在后台的线程不应该访问生命已结束的变量,特别是global和static变量。网上查找的资料(没有找到更权威的描述)指出,main()结束或者调用exit(),global或static变量会在子线程被终止前析构。也就是说,detached thread有可能访问到已被销毁或正在析构的global或static变量。

所以,使用detached thread时,应该:
1、detached thread 应尽可能只访问local copy。
2、detached thread 需要访问global或static变量时,应使用同步手段确保global或static变量在detached thread结束前不被销毁;或者以调用quick_exit()的方式结束程序,这个函数可以在程序结束时,不销毁global和static变量。

promise

promise对象可以用来存放一个值或者异常(称作shared state),但不能同时存放值和异常,存储了一个值或异常的promise是ready的。利用promise对象可以在线程之间传递参数、结果和异常。

1、支持的操作
操作作用
promise p默认构造函数,绑定shared state
promise p(allocator_arg, alloc)指定分配器构造promise对象
promise p(rv)移动构造函数
~promise()析构函数,释放shared state,如果它不是ready,就存储一个future_error异常,错误码为broken_promise
p = rv移动赋值操作符
swap(p1, p2)交换p1、p2状态
p1.swap(p2)交换p1、p2状态
p.get_future()创建一个用于取出shared state的future对象
p.set_value(val)设val为值并令状态为ready
p.set_value_at_thread_exit(val)在当前线程结束时设val为值并令状态为ready
p.set_exception(e)设e为异常并令状态为ready
p.set_exception_at_thread_exit(e)在当前线程结束时设e为异常并令状态为ready
2、异常

没有绑定shared state的promise对象调用get_future(),会抛出std::future_error异常,错误码是std::future_errc::no_state。
promise对象第只能调用一次get_future(),否则会抛出std::future_error异常,错误码是std::future_errc::future_already_retrieved。
promise对象只能调用一次set函数,否则会抛出std::future_error异常,错误码是std::future_errc::promise_already_satisfied。

try
{
	std::promise<int> p;
	std::promise<int> p1(std::move(p));					// 移动构造函数移走p的shared state,
	//p.get_future();										// 抛出future_error异常,错误码是no_state

	p1.set_value(10);
	//p1.set_value(10);									// 抛出future_error异常,错误码是promise_already_satisfied。

	p1.get_future();
	//p1.get_future();									// 抛出future_error异常,错误码是future_already_retrieved
}
catch (std::exception &e)
{
	std::cout << e.what() << std::endl;
}
3、set_xxxx函数

set_xxxx系列成员函数都是线程安全的。

packaged_task

packaged_task<>用来封装可调用对象及其结果(shared state)。类似function<>,但function<>不能封装结果。

1、支持操作

操作效果
packaged_task pt默认构造函数,packaged_task对象没有绑定shared state和可调用对象
packaged_task pt(f)构造函数
packaged_task pt(alloc, f)构造函数,指定分配器
packaged_task pt(rv)移动构造函数
~packaged_task()析构函数,释放shared state,且使shared state变成ready
pt = rv移动赋值操作符
swap(pt1, pt2)交换函数
pt1.swap(pt2)交换函数
pt.valid()pt拥有shared state时返回true
pt.get_future()返回一个future对象,用于读取shared state
pt(args)调用其封装的可调用对象,并使shared state变成ready
pt.make_ready_at_thread_exit(args)调用其封装的可调用对象,并在线程退出时使shared state变成ready
pt.reset()释放旧的shared state,使其变成ready,并建立一个新的shared state

2、异常

packaged_task对象没有绑定shared state时,调用绑定的可调用对象或者get_future会抛出std::future_error异常,错误码是std::future_errc::no_state。
第二次调用get_future会抛出std::future_error异常,错误码是std::future_errc::future_already_retrieved。
第二次调用可调用对象会抛出std::future_error异常,错误码是std::future_errc::promise_already_satisfied.

try
{
	std::packaged_task<int()> pt;
	pt.get_future();			// 抛出future_error异常,错误码no_state
	pt();						// 抛出future_error异常,错误码no_state

	std::packaged_task<int()> pt(std::bind(add, 1, 2));
	pt.get_future();
	pt.get_future();			// 抛出future_error异常,错误码future_already_retrieved

	pt();
	pt();						// 抛出future_error异常,错误码promise_already_satisfied
}
catch (std::exception &e)
{
	std::cout << e.what() << std::endl;
}

3、reset和析构

packaged task的析构函数和reset函数会释放shared state,并且如果shared state不是ready就令它变成ready,然后把一个std::future_error异常并夹带差错码std::future_errc::broken_promise存储在shared state中。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值