【C/C++】多线程编程
2021-01-17 07:14
标签:not join() 返回值 tor 最好 ble mina 时间 mutex Part1.【 thread 】(#include C++中的多线程,常通过thread类来定义一个thread对象(子线程)来实现。 thread t1 (func, arg1, arg2...); 其中func可以是一个函数名,或者函数对象;后边跟这个对象的参数; 在定义一个子线程以后,要确定他是join()或者detach()。 * t1.join():表示当前线程将在此处等待t1执行完相应操作后继续执行下面的程序(已经在运行状态的程序部分不会停止)。 * t1.detach(): 表示当前程序将不会等待以及管理t1子程序的运行。 * 一个子线程只能被join()或者detach()一次;一个子线程被detach后不可以再被join *必须规定子线程是join或者detach,否则程序会终止(terminate) 来看一个简单的代码示例: *************************************************************************************************************************************** Part2.【 mutex/locker/condition 】(#include 当多个线程同时使用或操作相同资源是,常会造成资源的混乱,例如两个线程同时在同一个队列或文件中进行写操作。 这种情况下我们可以用mutex类来生成一个对象,用来确保同一资源在同一时间内只被一个线程访问。 具体原理是,在使用某一资源时,如果前边有某个mutex对象mu.lock()的操作,则需先判断mu是否处于unlock的状态,如果没有的话说明被mu保护的该资源在被其他线程使用,则需要等待。 此外,由于一些特殊状况,例如异常,mu没有执行unlock, 会使被mutex对象保护的资源一直处于不能访问状态,我们经常把mutex与一些locker类结合使用,当locker对象生命周期结束时,无论通过任何方式结束,mutex对象都会被自动析构,资源便可释放。 常用的locker有:locker_guard和unique_locker。前一种效率较高,后一种功能较多更灵活,可控制locker的状态,也可与conditional_varialble结合使用。 * 死锁现象: 使用mutex和locker时要注意避免死锁现象,例如:线程A拥有mu1保护的资源,在等待mu2保护的资源;而线程B拥有mu2保护的资源,在等待mu1保护的资源 避免的方法有: 1. 一个mutex对象尽量只对应一个资源; 2. 若不得不安排多个mu对应一个资源,保持这些mu对象的顺序一致;最好使用std::lock(),包含一些避免死锁的机制 3. 不要在有对象被mutex保护时去call一个用户function/未知的function; * conditional_variable: (线程间交互) 在一些情况下,两个线程需要交互,其中一个线程需要等待另一个线程执行完一些操作才应该执行。 例如线程A负责往队列里放东西,线程B负责从队尾拿东西;如果A中push的操作还没有完成,B会一直查看队列中是否有元素,会导致性能的损耗。 这时会使用conditional_variable来建立一个A与B交流的方式。 比如下面一个列子: t1线程向dq中放入元素,t2从dq中取出元素; 输出结果为: 1 2 3 *********************************************************************************************************************************** Part3. 【 future/promise/async 】(#include 有时不同线程或程序的不同地方之间通信会有比较复杂的情况, Case1. 程序块A需要程序块B执行的函数的返回值。但程序块A不能控制程序块B什么时候结束,则可通过future对象(可以看做一个channel)来获取到将来某时刻B响应函数的返回值。 Eg. future int x = fu.get() //可获得函数myfunc的返回值 * async函数可理解为一个会并发进行的操作,与thread不同的是可以指定async中的操作是与当前线程同时进行还是需要时再触发, * async函数返回一个future对象 * 同一个future对象只可以使用一次get() Case2. 程序块A需要程序块B指定一些参数,但是在定义A时B还未设置该参数,则可传入一个future对象,并将其值等于一个promise对象,然后通过promise对象之后再设置具体的值。 Eg. future promise async(myfunc, ref(fu));... pr.set_value(...); 要注意的是promise对象使用后,一定要设置相应的值,不然会报错。 来看一个完整示例: myPow来计算一个数字x的n次方;通过future对象fp, 把参数x和n传入。而fp是通过promise对象pr来设置的。 此外myPow计算的结果又通过future对象fu传回。 运行结果为:16 ************************************************************************************************************ Part4【 packaged_task 】 另外一个callable 类型,基本定义为: packaged_task 其中T1是函数myFunc返回类型,T2..是myFunc的各函数类型;运行函数时应该使用:pt(arg1, arg2...); 一个packaged_task类型对象可以通过调用get_future()返回一个future对象 * 返回future类型的途径: 1. async(),函数直接返回类型; 2. promise对象,调用get_future(); 3. packaged_task对象,调用get_future(); 一个代码示例: 主线程中: 定义要执行thread_1的子线程t1, 定义要执行factorial的packaged_task t,并把他push到任务队列中, 通知t1: t1中: t1从任务队列中拿出t并执行factorial,执行结果被保存在t中(future channel中) 主线程中: t1结束后,从t中拿到结果 运行结果为:16 **以上内容参考相关视频: https://www.bilibili.com/video/BV1ut411y7u5** 【C/C++】多线程编程 标签:not join() 返回值 tor 最好 ble mina 时间 mutex 原文地址:https://www.cnblogs.com/xiyang2020/p/12919774.html#include
#include
#include
#include