#include
标准库提供了一些工具来获取异步任务(即在单独的线程中启动的函数)的返回值,并捕捉其所抛出的异常。这些值在共享状态中传递,其中异步任务可以写入其返回值或存储异常,而且可以由持有该引用该共享态的 std::future 或 std::shared_future 实例的线程检验、等待或是操作这个状态。
定义于头文件
Future 错误
#include
#include
#include
#include
#include
#include
using namespace std;
int do_something(char c){
//初始化了一个随机数引擎和一个随机数分布
default_random_engine dre(c);
uniform_int_distribution id(10,1000);
for(int i =0;i<10;++i){
//随机停止一段时间。
this_thread::sleep_for(chrono::milliseconds(id(dre)));
cout.put(c).flush();
}
return c;
}
int func1(){
return do_something('.');
}
int func2(){
return do_something('+');
}
int main(){
//启动异步线程,执行函数1。使用future作为占位符
//async的返回值与func1自动匹配,是模板函数。
//future object的类型也可以与async自动匹配,设置成auto result1()
//async接受任何可调用对象。包括函数、函数指针、lambda函数
future result1(async(func1));
//主线程中执行函数2
int result2 = func2();
int result=0;
try
{
result = result1.get()+result2;
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
//计算结果,阻塞主线程
//输出结果
cout<
函数名字 | 作用 |
---|---|
get | 调用future.get()函数会阻塞线程。等待另一个线程结束返回结果。如果不调用get函数。则main函数在结束前会等待这个线程结束并返回。get函数会捕获线程内的异常抛出,可以在get外捕获异常 |
valid | future.valid()检测线程是否处于正常运行状态还是已经退出。 |
wait | future.wait()函数会阻塞线程。但不需要获得返回结果。 |
wait_for | future.wait_for(std::chrono::seconds(10));等待最多10秒 |
wait_until | future.wait_until(system_clock::now()+chrono::minutes(1));等待当前时间后一分钟。 |
常量 | 解释 |
---|---|
deferred | 共享状态含有延迟的函数,故将仅在显式请求时计算结果 |
ready | 共享状态就绪 |
timeout | 共享状态在经过指定的时限时长前仍未就绪 |
#include
函数 | 作用 |
---|---|
joinable | 检查线程是否可合并,即潜在地运行于平行环境中(公开成员函数) |
get_id | 返回线程的 id(公开成员函数) |
native_handle | 返回底层实现定义的线程句柄(公开成员函数) |
hardware_concurrency | [静态]返回实现支持的并发线程数(公开静态成员函数) |
函数 | 作用 |
---|---|
join | 等待线程完成其执行 |
detach | 容许线程从线程句柄独立开来执行 |
#include
#include
#include
#include
#include
using namespace std;
void doSomething(int num,char c){
try
{
default_random_engine dre(42*c);
uniform_int_distribution id(10,1000);
for(int i=0;i
提供了异步通信的方法。async相当于自动设置了promise推端,利用return语句抛出一个promise,解锁future.get的阻塞;使用thread启动线程的话,需要手动设置promise实现信号发出,接触future.get的阻塞。
函数 | 作用 |
---|---|
get_future | 返回与承诺的结果关联的 future(公开成员函数) |
set_value | 设置结果为指定值(公开成员函数) |
set_value_at_thread_exit | 设置结果为指定值,同时仅在线程退出时分发提醒(公开成员函数) |
set_exception | 设置结果为指示异常(公开成员函数) |
set_exception_at_thread_exit | 设置结果为指示异常,同时仅在线程退出时分发提醒(公开成员函数) |
#include
#include
#include
#include
#include
#include
#include
using namespace std;
void doSomething(promise& p){
try{
cout<<"read char x for exception"<p;
thread t(doSomething,std::ref(p));
t.detach();
future f(p.get_future());
cout<<"result:"<
函数 | 作用 |
---|---|
get_future | 返回与承诺的结果关联的 std::future |
operator() | 执行函数 |
make_ready_at_thread_exit | 执行函数,并确保结果仅在一旦当前线程退出时就绪 |
reset | 重置状态,抛弃任何先前执行的存储结果 |
//线程执行的函数
double doSomething(int x,int y);
//申请一个线程池。
package_task task(doSomething);
//获得线程池的future
future f = task.get_future();
//使用线程池启动一个县城
task(7,5);
//使用future获得线程执行的结果。
double res = f.get();
多个线程共享资源出现访问冲突
保证操作的原子性和次序。atomicity不可分割。order按次序执行。
函数 | 作用 |
---|---|
lock | 锁定互斥,若互斥不可用则阻塞 |
try_lock | 尝试锁定互斥,若互斥不可用则返回 |
unlock | 解锁互斥 |
int val ;
mutex valMutex;
valMutex.lock();
//val的访问和修改
valMutex.unlock();
mutex m;
while(m.try_lock()==false){
doSomethingOthers();
}
lock_guard lg(m,adopt_lock);
函数 | 作用 |
---|---|
lock | 锁定互斥,若互斥不可用则阻塞 |
try_lock | 尝试锁定互斥,若互斥不可用则返回 |
try_lock_for | 尝试锁定互斥,若互斥在指定的时限时期中不可用则返回 |
try_lock_until | 尝试锁定互斥,若直至抵达指定时间点互斥不可用则返回 |
(公开成员函数) | |
unlock | 解锁互斥 |
try_lock_for()
try_lock_until()
std::lock_guard sbguard1(my_mutex1, std::adopt_lock);// std::adopt_lock标记作用;
//mute & lock
#include
#include
#include
#include
using namespace std;
//互斥体的控制变量
mutex printMutex;
void print(const std::string&s){
// 如果没有枷锁,多个线程共同调用会乱序输出
lock_guard l(printMutex);
for(char c:s){
cout.put(c);
}
cout<
函数 | 作用 |
---|---|
lock | 锁定关联互斥 |
try_lock | 尝试锁定关联互斥,若互斥不可用则返回 |
try_lock_for | 试图锁定关联的可定时锁定 (TimedLockable) 互斥,若互斥在给定时长中不可用则返回 |
try_lock_until | 尝试锁定关联可定时锁定 (TimedLockable) 互斥,若抵达指定时间点互斥仍不可用则返回 |
unlock | 解锁关联互斥 |
release | 将关联互斥解关联而不解锁它.返回unique_lock所有的锁的指针。可以自己解锁 |
mutex | 返回指向关联互斥的指针 |
owns_lock | 测试锁是否占有其关联互斥 |
operator bool | 测试锁是否占有其关联互斥 |
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D0CxYST2-1691409363748)(image/2021-03-08-18-31-27.png)]
void shared_print(string msg, int id) {
std::unique_lock guard(_mu);
//do something 1
guard.unlock(); //临时解锁
//do something 2
guard.lock(); //继续上锁
// do something 3
f << msg << id << endl;
cout << msg << id << endl;
// 结束时析构guard会临时解锁
// 这句话可要可不要,不写,析构的时候也会自动执行
// guard.ulock();
}
condition_variable 类是同步原语,能用于阻塞一个线程,或同时阻塞多个线程,直至另一线程修改共享变量(条件)并通知 condition_variable 。
有意修改变量的线程必须
即使共享变量是原子的,也必须在互斥下修改它,以正确地发布修改到等待的线程。
任何有意在 std::condition_variable 上等待的线程必须
condition_variable的消费者。有一下三种情况。
- 当资源没有被生产出来,没有加锁时,加锁,wait(),解锁,等待通知。
- 当资源被锁时,在unique_lock处等待解锁。
- 当资源生产出来,没有加锁时,直接执行。
对于第一种情况:condition_varaiblewait操作能够解锁等待信号量。当信号量来到时,加锁执行操作,然后解锁,退出。当信号量来到时,加锁,但是第二个参数的内容发现是虚假信号,能够继续解锁等待信号量。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1mPFSc4a-1691409363749)(image/2021-03-08-19-36-00.png)]
函数 | 作用 |
---|---|
notify_one | 通知一个等待的线程 |
notify_all | 通知所有等待的线程 |
wait | 阻塞当前线程,直到条件变量被唤醒 |
wait_for | 阻塞当前线程,直到条件变量被唤醒,或到指定时限时长后 |
wait_until | 阻塞当前线程,直到条件变量被唤醒,或直到抵达指定时间点 |
//condition variable生产者消费者问题
#include
#include
#include
#include
using namespace std;
bool readyFlag;
mutex readyMutex;
condition_variable readyCondVar;
void thread1(){
cout<<"thread1"< lg(readyMutex);
readyFlag = true;
}
readyCondVar.notify_one();
}
void thread2(){
{
unique_lock ul(readyMutex);
readyCondVar.wait(ul,[]{return readyFlag;});
}
cout<<"done"<
//condition variable实现多线程queue
#include
#include
#include
#include
#include
#include
using namespace std;
queue que;//消费对象
mutex queueMutex;
condition_variable queueCondVar;
//生产者
void provider(int val){
for(int i=0;i<6;++i){
lock_guard lg(queueMutex);
que.push(val+i);
//貌似这句话会被优化掉
this_thread::sleep_for(chrono::microseconds(100000));
}
queueCondVar.notify_one();
this_thread::sleep_for(chrono::microseconds(val));
}
//消费者
void consumer(int num){
while(true){
int val;
{
unique_lock ul(queueMutex);
queueCondVar.wait(ul,[]{return !que.empty();});
val = que.front();
que.pop();
cout<<"consumer"<
等到以后再写吧。感觉没有必要。
函数 | 作用 |
---|---|
get_id | 获得thread id (function ) |
yield | 放弃执行 (function ) |
sleep_until | 休眠到某个时间节点chrono::timepoint (function ) |
sleep_for | 休眠某个时间段chrono::duration (function ) |