c++多线程并发实战pdf,c++多线程并发编程

  c++多线程并发实战pdf,c++多线程并发编程

  线程同步主要是解决对共享数据的争用访问问题,所以线程同步主要是同步对共享数据的访问(按照既定的顺序,一个访问需要阻塞到前一个访问完成后才能开始)。本文提到的异步编程,主要是针对任务或线程的执行顺序,即一个任务不需要被阻塞,等待最后一个任务完成才开始执行,程序的执行顺序与任务的排列顺序不一致。下面从任务执行顺序的角度解释同步和异步的区别:

  同步:当进行一个调用时,在获得结果之前,调用不会返回。但是一旦调用返回,您将获得返回值。换句话说,调用者主动等待这个调用的结果。

  异步:发出调用后,这个调用直接返回,所以不返回结果。换句话说,当发出异步过程调用时,调用者不会立即得到结果。而是在调用发出后,被调用方通过状态和通知通知调用方,或者通过回调函数处理调用。

  二、如何使用异步编程

  在线程库线程中,没有办法得到线程的执行结果。通常情况下,线程调用者需要获取线程的执行结果或执行状态,以便执行后续任务。那么,如何才能获得被调用者的执行结果或状态呢?

  2.1使用全局变量和条件变量传递结果。

  上面提到的条件变量有“通知-唤醒”的功能,可以把执行结果或者执行状态放到一个全局变量中。当被调用方完成任务时,条件变量通知调用方结果或状态已经更新,可以使用了。下面是一个程序示例:

  //future1.cpp使用全局变量传递被调用线程返回的结果,使用条件变量通知调用线程已经获得结果。

  #包括

  #包括

  #包括

  #包括

  #包括

  #包括

  #包括

  int RES=0;//保存结果的全局变量

  std:互斥mu;//互斥全局变量

  STD:condition _ variable cond;//全局条件变量

  void accumulate(STD:vector:iterator first,

  std:vector:iterator last)

  {

  int sum=std:accumulate(first,last,0);//标准库求和函数

  std:unique_lock锁柜(mu);

  res=sum

  locker . unlock();

  cond . notify _ one();//向等待线程发送“条件满足”通知

  }

  int main()

  {

  std:矢量数={ 1,2,3,4,5,6 };

  STD:thread work _ thread(accumulate,numbers.begin()、numbers . end());

  std:unique_lock锁柜(mu);

  cond.wait(locker,[](){ return RES;});//如果条件变量被唤醒,检查结果是否被改变。如果是真的,直接退回;如果是假的,就继续等。

  STD:cout result= RES \ n ;

  locker . unlock();

  work _ thread . join();//阻塞并等待线程执行完成

  getchar();

  返回0;

  }函数执行结果如下:

  从上面的代码可以看出,虽然也实现了获取异步任务执行结果的功能,但是需要的全局变量比较多,多线程之间的耦合度比较高,在编写复杂程序的时候很容易引入bug。有没有更好的实现异步编程的方法?C 11增加了一个未来库函数,为异步编程提供了极大的便利。

  2.2利用承诺和未来交付成果

  未来的头文件函数允许异步访问由特定提供者设置的值,可能在不同的线程中。

  这些提供者(promise对象、packaged_task对象或对async的异步调用)与未来对象共享共享状态:提供者将共享状态就绪的点与未来对象访问共享状态的点同步。未来头文件的结构如下:

  注意前面提到的共享状态。多线程传递的返回值或异常都是在共享状态下传递的。我们知道多线程并发访问共享数据时需要保持同步,这里的共享状态是保证线程间正确传递返回值或异常的关键。被调用线程可以通知调用线程,返回值或异常已经写入,可以通过改变共享状态来访问或操作。未来的状态(future_status)有以下三种:

  延迟:异步操作尚未开始;

  就绪:异步操作已经完成;

  超时:异步操作超时。

  由于线程间返回值或异常的传递是通过共享状态进行的,所以涉及到共享状态的提供者和获取者。只有当任务或线程拥有包含共享状态的对象时,其他任务或线程才能通过共享状态的通知机制同步获取该人或线程的返回值或异常。我们通常用来创建线程的线程没有共享状态,所以我们需要为它提供一个共享状态,以便后续访问它的返回值或异常。那么,如何为线程提供具有共享状态的对象呢?这需要借助std:promise T模板来实现,具体用法如下:

  std:promise T构造时,会生成一个未就绪的共享状态(包括存储的T值和就绪状态)。可以设置t的值,使状态为就绪。还可以通过生成一个future对象来获得就绪共享状态下的t值。继续使用上面的程序示例,而不是使用promise来交付结果。修改后的代码如下:

  //future2.cpp使用promise传递被调用线程返回的结果,通知调用线程已经通过共享状态变化获得结果。

  #包括

  #包括

  #包括

  #包括

  #包括

  #包括

  void accumulate(STD:vector:iterator first,

  std:vector:iterator last,

  标准:承诺累计_承诺)

  {

  int sum=std:accumulate(first,last,0);

  accumulate _ promise . set _ value(sum);//将结果保存在中,并使共享状态准备好提醒未来。

  }

  int main()

  {

  //演示用promise在线程之间传递结果。

  std:矢量数={ 1,2,3,4,5,6 };

  STD:promise accumulate _无极;

  STD:future accumulate _ future=accumulate _ promise . get _ future();

  STD:thread work _ thread(accumulate,numbers.begin(),numbers.end(),

  STD:move(accumulate _ promise));

  accumulate _ future . wait();//等待结果

  STD:cout result= accumulate _ future . get() \ n ;

  work _ thread . join();//阻塞并等待线程执行完成

  getchar();

  返回0;

  }std:promise T对象的成员函数get_future()生成一个std:future T对象。代码示例中显示了Future object的两个方法:wait()和get()。以下是更多操作功能供参考:

  值得注意的是std:future T在多个线程等待的情况下只有一个线程可以得到等待结果。当多个线程需要等待同一个事件的结果时(即多次访问同一个共享状态),应该使用std:shared_future T,而不是std:future T,STD: future T还提供了一个方法f.share()将future转换为shared_future,但转换后原来的future状态就失效了。这有点类似于智能指针中std:unique_ptr T和std:shared_ptr T的关系,使用时要注意。

  2.3使用packaged_task和future来交付结果,不仅可以为一个任务或线程提供一个包含共享状态的变量,还可以直接将共享状态封装到一个任务或线程中。这需要通过std:packaged_task Func来实现,具体用法如下:

  Std:packaged_task Func在构造的时候就绑定了一个函数对象,同样会产生一个无准备的共享状态。通过线程或模仿函数的形式启动函数对象。但是和promise相比,没有set_value()公共接口。而是在执行绑定的函数对象时,其执行结果返回值或抛出的异常存储在一个共享状态下,可以通过std:future对象访问。继续上面的程序示例,改为使用packaged_task来传递结果。修改后的代码如下:

  //future3.cpp使用packaged_task传递被调用线程返回的结果,通知调用线程已经通过共享状态变化获得结果。

  #包括

  #包括

  #包括

  #包括

  #包括

  #包括

  int accumulate(STD:vector:iterator first,

  std:vector:iterator last)

  {

  int sum=std:accumulate(first,last,0);

  返回总和;

  }

  int main()

  {

  //演示用packaged_task在线程间传递结果。

  std:矢量数={ 1,2,3,4,5,6 };

  std:packaged_task:iterator,STD:vector:iterator)accumulate _ task(accumulate);

  STD:future accumulate _ future=accumulate _ task . get _ future();

  STD:thread work _ thread(STD:move(accumulate _ task),numbers.begin(),numbers . end());

  accumulate _ future . wait();//等待结果

  STD:cout result= accumulate _ future . get() \ n ;

  work _ thread . join();//阻塞并等待线程执行完成

  getchar();

  返回0;

  }一般来说,不同函数之间的数据传递主要通过全局变量、返回值、函数参数等方式来实现。上面第一种方法使用全局变量来传递数据,会使得不同函数之间的耦合度高,不利于模块化编程。后两种方法分别通过函数参数和返回值传递数据,可以降低函数之间的耦合度,编程和维护更简单快捷。

  2.4使用异步交付结果

  前面介绍的std:promise T和std:packaged_task Func已经提供了丰富的异步编程工具,但是在使用它们的时候,既要创建提供共享状态的对象(promise和packaged_task),又要创建访问共享状态的对象(future和shared_future),否则使用起来不够方便。有没有更简单的异步编程工具?未来头文件确实封装了更高级的函数std:async,具体用法如下:

  std:future std:async(std:启动策略,函数,参数…)

  Std:async是一个函数而不是类模板,函数执行后的返回值使用std:async绑定到std:futrue对象(std:async实际上封装了thread的函数,packed _ task,这样更方便异步执行一个任务)。Func是要调用的可调用对象(函数、成员函数、函数对象、lambda),Args是传递给func的参数,std:launch policy是启动策略,控制std:async的异步行为。我们可以用三种不同的启动策略创建std:async:

  Std:launch:async参数保证异步行为,即传递函数将在单独的线程中执行;

  Std:launch:deferred参数当其他线程调用get()/wait()访问共享状态时,会调用非异步行为;

  STD:launch:async STD:launch:deferred参数是默认行为(可以省略)。使用这种启动策略,它可以异步运行,也可以不异步运行,这取决于系统的负载。

  继续上面的程序示例,改为使用std:async来传递结果。修改后的代码如下:

  //future4.cpp使用async传递被调用线程返回的结果。

  #包括

  #包括

  #包括

  #包括

  #包括

  #包括

  int accumulate(STD:vector:iterator first,

  std:vector:iterator last)

  {

  int sum=std:accumulate(first,last,0);

  返回总和;

  }

  int main()

  {

  //演示如何使用异步在线程之间传递结果。

  std:矢量数={ 1,2,3,4,5,6 };

  auto accumulate _ future=STD:async(STD:launch:async,accumulate,numbers.begin()、numbers . end());//auto可以自动推断变量的类型。

  STD:cout result= accumulate _ future . get() \ n ;

  getchar();

  返回0;

  }从上面的代码可以看出,使用std:async可以大大减少编程工作量,这样我们就可以方便地获得异步执行的状态和结果,而不需要关注线程创建的内部细节,还可以指定线程创建策略。所以,我们可以使用std:async来代替线程创建,使之成为异步操作的首选。

  空谈不值钱。给我看看代码

  转载请联系作者取得转载授权,否则将追究法律责任。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • php读取pdf数据,php pdf读取
  • php读取pdf数据,php pdf读取,PHP中使用mpdf 导出PDF文件的实现方法
  • kotlon协程,深入理解kotlin协程pdf,一文彻底搞懂Kotlin中的协程
  • 深入解析C#(第4版),深入解析css pdf,深入解析contentWindow, contentDocument
  • java 反射机制原理与用法详解视频,java 反射机制原理与用法详解pdf
  • java 反射机制原理与用法详解视频,java 反射机制原理与用法详解pdf,Java 反射机制原理与用法详解
  • ,,Java使用iTextPDF生成PDF文件的实现方法
  • ,,Python利用PyMuPDF实现PDF文件处理
  • 漫画算法小灰的算法之旅pdf,漫画算法2-小灰的算法进阶
  • devops和自动化运维实践 PDF,devops思想在运维方面的具体实践
  • pdf如何去除水印,pdf去水印的三种方法
  • 把a4的内容打印成a3小册子,a4的pdf文档如何打印成a3
  • nlp自然语言处理入门pdf,精通python自然语言处理 pdf
  • 容器docker基本操作,每天5分钟玩转docker容器技术 pdf
  • sklearn中文手册pdf下载,sklearn库模块及函数
  • 留言与评论(共有 条评论)
       
    验证码: