并发低层接口: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
    评论
std::promiseC++11并发编程中常用的一个类,常配合std::future使用。它的作用是在一个线程中保存一个特定类型的值,供与之绑定的std::future对象在另一个线程中获取。\[1\] 下面是一个示例代码,展示了std::promise的使用方法: ```cpp #include <iostream> #include <future> #include <chrono> void Thread_Fun1(std::promise<int>& p) { std::this_thread::sleep_for(std::chrono::seconds(5)); int iVal = 233; std::cout << "传入数据(int):" << iVal << std::endl; p.set_value(iVal); } void Thread_Fun2(std::future<int>& f) { auto iVal = f.get(); std::cout << "收到数据(int):" << iVal << std::endl; } int main() { std::promise<int> pr1; std::future<int> fu1 = pr1.get_future(); std::thread t1(Thread_Fun1, std::ref(pr1)); std::thread t2(Thread_Fun2, std::ref(fu1)); t1.join(); t2.join(); return 0; } ``` 在这个示例中,我们创建了一个std::promise对象pr1,并通过pr1的get_future()函数与一个std::future对象fu1绑定。然后我们创建了两个线程t1和t2,分别执行Thread_Fun1和Thread_Fun2函数。在Thread_Fun1中,我们通过set_value()函数将一个整数值传入pr1。在Thread_Fun2中,我们通过阻塞函数get()获取到了传入的数据,并进行输出。\[2\] 从示例中可以看到,std::promise对象可以保存各种类型的数据,包括函数指针等。\[3\] #### 引用[.reference_title] - *1* *2* *3* [[C++11]std::promise](https://blog.csdn.net/weixin_43743711/article/details/115770638)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值