C++多线程代码,c++多线程是什么意思

  C++多线程代码,c++多线程是什么意思

  终于在千呼万唤的指引下,C 11有了自己的线程库,实现了真正的跨平台。今天,在学习C 11线程库的同时,我还将回顾POSIX线程。

  C 11之前的POSIX线程,因为没有C语言,也没有语言级线程库,所以所有的POSIX线程都用在Linux上。POSIX的相关API如下:

  POSIX函数pthread_create创建线程pthread_exit退出线程pthread_join等待线程退出pthread_cancel取消线程pthread_detach线程detach pthread_self获取线程idpthread_equal比较是否是同一个线程,返回0是同一个线程1、创建线程

  创建的线程的原型是:

  int pthread _ create(pthread _ t _ Nullable * _ Nonnull _ _ restrict,const pthread _ attr _ t * _ Nullable _ _ restrict,void * _ Nullable(* _ Nonnull)(void * _ Nullable),void * _ Nullable _ _ restrict);其中pthread_t是线程id,只需传入一个指针。如果成功创建,它将被指定为所创建线程的id。

  Pthread_attr_t是创建线程所需的参数。通过这些参数,可以定制线程的属性,例如新创建的线程堆栈的大小、调度策略等。如果不需要传递NULL。

  第三个参数是函数指针,是线程需要成功执行的具体任务函数。

  第四个是线程带一个参数,这个参数会在线程的函数指针执行的时候传递。

  例如:

  class { public:void do something(){ STD:cout 子线程ID: pthread _ self()STD:endl;Std:cout 做点什么 STD:endl;}};void * doWork(void * args){ Task * Task=static _ cast Task *(args);if(nullptr!=task){ task-do something();}}int main() {std:cout 主线程的线程ID: pthread _ self()STD:endl;//创建线程pthread _ t pthread任务task;pthread_create( pthread,nullptr,doWork,task);pthread_join(pthread,nullptr);//线程等待执行完成。返回0;}2、线程退出

  退出线程的正确方法是在连接之前退出线程。

  因为如果线程退出后不进行连接操作,线程的资源就不能被释放和重用,从而导致资源的泄露。

  所谓join操作,就是在线程退出后使用pthread_join。

  其他线程功能这里就不细说了,因为今天的主要内容是C 11的线程知识。

  关于POSIX线程的更多知识,笔者之前看过《Linux环境编程XXXX》(为避免广告,我就不写书名全称了),挺好的。

  C 11线程我们先来看一个C 11多线程的例子:

  void work(){ STD:cout doing something STD:endl;} int main(){ thread thread(doWork);STD:cout thread . join able: thread . join able()STD:endl;thread . join();STD:cout thread . join able: thread . join able()STD:endl;返回0;}是不是比POSIX线程简洁很多?

  1.螺纹分离

  在上面的例子中,如果我们将join改为detach,就意味着我们不再接管这个线程,相当于驻留在后台,完全被C运行时库接管。当线程运行时,C运行库会清理相关的线程资源。

  需要注意的是,在上面的例子中,如果将join改为detach,很可能看不到输出,但这是正常的,线程一旦被分离,就不能再被连接了。

  对于一个线程,我们可以通过joinable函数来判断它是可连接的还是可分离的。如果线程已经被加入或分离,那么joinable将返回false。

  2.线程传递参数

  如果我们想在线程执行的时候给线程传递参数呢?

  如果我们需要给线程传递参数,那么我们只需要在线程执行完函数后添加参数,然后将实际的参数传递给线程的构造函数,例如:

  Void doWork(int a) {std:cout I是传递的参数a: a STD:endl;Std:cout 做点什么 STD:endl;}int main() { thread thread(doWork,100);//传递参数thread.join()示例;返回0;}既然涉及到参数传递,那就回到C的老问题了。向线程传递参数时,是通过值、指针还是引用传递参数?

  让我们先来看看下面的例子:

  void doWork(const int a){ this _ thread:sleep _ for(STD:chrono:seconds(1));//休眠std:cout 我是传递的参数A的地址: A STD:endl;Std:cout I是传递的参数a: a STD:endl;} void threadTest(){ int a=130;std:cout a的地址: a STD:endl;螺纹thread(doWork,a);} int main(){ threadTest();this _ thread:sleep _ for(STD:chrono:seconds(3));//休眠3s,让子线程执行返回0;}理论上,上面的例子是有问题的。为什么?线程是在函数threadTest中打开的,但是当函数返回时,堆栈变量thread被销毁,所以我们看到它运行时会报错。以下是输出:

  libabi:Terminating//注意,这是错误A的地址:0x16f2fb7cc。所以如果我们要在函数内部启动一个线程,就需要在线程的任务执行结束之前,保持线程变量thread不被破坏,需要使用堆指针或者局部变量。

  让我们首先测试值的传递方式:

  Class {public: task () {STD: cout 构造函数,线程id: this _ thread:get _ id()STD:endl;} task(const task task):a(task . a){ STD:cout 复制构造,线程id: this _ thread:get _ id()STD:endl;} ~Task(){ std:cout 析构函数,线程id: this _ thread:get _ id()STD:endl;} void do something()const { STD:cout -做点什么。现在是什么: a STD:endl;} public:int a;};void Dowork(task task){ STD:cout -Dowork线程id: this _ thread:get _ id()STD:endl;this _ thread:sleep _ for(STD:chrono:seconds(1));//Hibernate std:cout 我是传递的参数地址: task STD:endl;//执行任务task . do something();} void threadTest(){ Task Task;task.a=100 Std:cout 原始地址: task STD:endl;//为了防止线程变量被破坏,这里使用堆指针进行测试,暂时不考虑指针释放thread * th=new thread (dowork,task);Std:cout 线程id: th-get _ id()STD:endl;th-join();}int main() {std:cout 主线程id: STD:this _ thread:get _ id()STD:endl;threadTest();this _ thread:sleep _ for(STD:chrono:seconds(3));//休眠3s,让子线程执行返回0;}以下是输出:

  主线程id:0x1050a4580构造函数,线程id:0x1050a4580原始地址:0x16af237bc复制构造,线程id:0x1050a4580复制构造,线程id:0x1050a4580析构函数,线程id:0x1050a4580线程id:0x16afab000复制构造线程id:0x16afab000-Dowork线程id:0x16afab000 Im传递的参数地址:0x16afab3c -做点什么。现在是什么?100析构函数,线程id:0x16afab000析构函数,线程Thread id:0x1050a4580在上面的测试中,我们发现如果是通过值传递,如果需要使用多个线程,我们会经历三次复制的过程,确实有点性能消耗。

  不是说引用可以减少抄袭吗?我们来测试一下引用是怎么通过的,还是上面的程序。让我们修改一下函数doWork。

  void working(const task task){ STD:cout -dowork线程id: this _ thread:get _ id()STD:endl;this _ thread:sleep _ for(STD:chrono:seconds(1));//Hibernate std:cout 我是传递的参数地址: task STD:endl;//执行任务task . do something();}看输出:

  主线程id:0x1041f0580构造函数,线程id:0x1041f0580原地址:0x16bcc77bc复制构造,线程id:0x1041f0580复制构造,线程id:0x1041f0580析构函数,线程id:0x1041f0580线程id:0x16bd4f000-Dowork线程id:0x16bd4f000我是传递的参数地址:0x 6000016 c 111110-做点什么

  其实指不抄就传,是为了直接调用。这里的多线程调用,系统不会马上为你调用任务函数,而是需要内部N次封装才能调用开发者制定的任务函数。没有中间商赚差价也是相对的。

  注意:虽然使用了引用,但是内部是复制的,所以如果要传递引用,那么在线程函数内部修改值,然后在线程函数外部工作,这个思路是行不通的。

  我们来看看指针的传递。让我们修改函数threadTest和doWork。

  void working(task * task){ STD:cout -dowork线程id: this _ thread:get _ id()STD:endl;this _ thread:sleep _ for(STD:chrono:seconds(1));//Hibernate std:cout 我是传递的参数地址: task STD:endl;//执行任务task-do something();} void threadTest(){ Task * Task=new Task;任务-a=100; Std:cout 原始地址: task STD:endl;//为了防止线程变量被破坏,这里使用堆指针进行测试,暂时不考虑指针释放thread * th=new thread (dowork,task);Std:cout 线程id: th-get _ id()STD:endl;}输出:

  主线程id:0x1009fc580构造函数,线程id:0x1009fc580原地址:0x600033ac030线程id:0x16f63b000-dowork线程id:0x16f63b000我是传递的参数地址:0x6000033ac030 -。A: 100现在的数字是多少?令人惊讶的是,没有对象的副本。虽然里面还有指针的副本,但是这个损失可以忽略。看来如果要给多线程传递参数,还是要获取指针。

  既然是指针,就要陷入谁维护谁释放的漩涡。

  试试智能指针?或者修改函数threadTest和doWork。

  void work(const shared _ ptrtaskptr){ STD:cout -dowork线程id: this _ thread:get _ id()STD:endl;this _ thread:sleep _ for(STD:chrono:seconds(1));//休眠std:cout 我是传递的参数地址: ptr STD:endl;//执行任务ptr-do something();} void threadTest(){ shared _ ptr Task ptr=make _ shared Task ptr-a=100;Std:cout 原始地址: ptr . get()STD:endl;//为了防止线程变量被破坏,这里使用堆指针进行测试,暂时不考虑指针释放thread *th=new thread(doWork,ptr);Std:cout 线程id: th-get _ id()STD:endl;}输出:

  主线程id:0x10502c580构造函数,线程id:0x10502c580原地址:0x600000d9118线程id:0x16b033000-dowork线程id:0x16b033000 I是传递的参数地址:0x6000000d9118 -。什么是now: 100析构函数,线程id:0x16b033000摘要1。如果给线程任务传递参数,如果是一般的数据类型,比如int,建议直接用值传递。

  2.如果传递复杂类的参数,建议使用智能指针。

  推荐阅读《C++之指针扫盲》

  《C++之智能指针》

  《C++之指针与引用》

  《C++之右值引用》

  关注我,共同进步,生活不止编码!

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

相关文章阅读

  • pthread线程包常用函数,pthread多线程编程
  • c 多线程编程,c多线程编程实例
  • c 多线程编程,c多线程编程实例,VC多线程编程详解
  • cas 并发,java多线程cas
  • cas 并发,java多线程cas,java并发编程之cas详解
  • android中实现多线程操作的几种方式是什么,android 的多线程 实现方法
  • android中实现多线程操作的几种方式是什么,android 的多线程 实现方法,Android中实现多线程操作的几种方式
  • ,,详解Java多线程tryLock()方法使用
  • python多线程详解,python中的线程和进程
  • python多线程详解,python中的线程和进程,Python线程详解
  • ,,python多线程高级锁condition简单用法示例
  • ,,.NET Windows 多线程thread编程
  • python多线程是不是真正的并发,python的多进程是并发还是并行
  • python 多线程并行处理,python多线程运行
  • python 多线程编程,python多线程有几种实现方法,都是什么
  • 留言与评论(共有 条评论)
       
    验证码: