打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
C++11undefinedThread多线程的学习心得与问题

C++11 ,封装了thread的多线程的类,这样对多线程的使用更加方便。

多线程的原理我不加赘述,可以参看操作系统等参考书。

多线程代码可以最大化利用计算机性能资源,提高代码的运行效率,是常用优化方法。

我不是C++大神,初学阶段的菜鸟而已,很多问题我还是不理解当中的原理,写这篇博客的原因,也是记录自己的学习心得和思路,供自己日后自己思考。

首先从简单的问题入手,如何写一个多线程的C++代码?

#include<iostream>#include<thread>void fun(int a){    a++;}int main(){    int a=0;    std::thread t(fun,a);  //创建一个线程t,t调用函数fun,a作为fun的参数,也要写到thread的构造函数当中;
t.join(); //启动线程t,并且阻塞主线程,等到线程t运行结束后,再继续运行主线程; std::cout
<<a<<std::endl;}

上面这段代码是最简单的多线程代码,调用thread类,并利用了thread的构造函数创建一个线程t,thread类的构造函数重载了很多,后面会继续说到。

在这里要说一下,thread类当中的两个成员函数,join()和detach()。这两个成员的作用就像上面代码的注释那样,启动新生成的线程的,但是区别在于join()函数是启动子线程而阻塞主线程,当子线程运行结束后,才会继续运行主线程。相比之下,detach()函数的作用是启动子线程,并且让子线程和主线程分离,子线程和主线程各运行各的,虽然两个线程会因为共享内存池的原因在操作系统的层面发生发生阻塞等关系,但是在代码层次上,两个线程并不存在谁阻塞谁,很可能主线程已经运行结束了,子线程还在运行。

接下来,我们要说一下类当中的成员函数如何初始化thread类的构造函数。

对于类的成员函数,我们需要给出类对象的地址:

#include<iostream>#include<thread>class A{public:    void fun(int a,int b){        std::cout<<"this is A thread!"<<a<<std::endl;    }};int main(){    int k=0;    A a;    std::thread t(&A::fun,a,k,k+1);       t.join();}
std::thread t(&A::fun,a,k,k+1);  这个地方就可以看出thread类的构造对于成员函数的重载了,std::thread t(函数(成员函数)地址,对象地址,成员函数的参数1,参数2,参数3...)。
相比非成员函数,成员函数需要给出类实例化对象的地址,如果该线程是在同一类的某一成员函数当中被构造,则直接用this关键字代替即可。

其实,我在写成员函数的多线程代码的时候,发现成员函数的需要传递的参数太多会使thread类的构造函数重载失败,我测试了一下,成员函数最多只能传递4个参数,也就说std::thread类的构造函数最多只能重载6个参数。
这一点,我并没有找到相关文档得到证实,只是在写代码的时候发现成员函数传递参数太多,会一直编译不通过,偶然间发现这个点的,具体到底对不对,我也不是很确定。

其次,我们要说一下加锁和解锁的问题。
因为我们创造的每一个线程只要在一个进程内,都是共享内存池的,这样在读写数据可能会发生混乱。
C++11提供了mutex类进行加锁和解锁。
#include<iostream>#include<thread>#include<mutex>std::mutex mut;class A{public:    volatile int temp;    A(){        temp=0;    }    void fun(int num){        int count=10;        while(count>0){            mut.lock();            temp++;            std::cout<<"thread_"<<num<<"...temp="<<temp<<std::endl;            mut.unlock();            count--;        }    }    void thread_run(){            std::thread t1(&A::fun,this,1);               std::thread t2(&A::fun,this,2);            t1.join();            t2.join();    }};int main(){    A a;    a.thread_run();}

然后,我们说一下volatile关键字。

volatile和const关键很相似,都是修饰变量的,只是二者功能不一样。
volatile在多线程当中经常使用,因为在某一线程多次调用某一个变量,编译器会进行优化,将该变量存放在在寄存器当中,不会每次都从内存当中读入。果然该变量同时在其他线程当中被修改,这样就会发生脏读取错误。

而加上volatile修饰,则会提醒编译器,这个变量可能会被改变,不能存放到寄存器当中,需要每次都从内存当中读取。
最后,我们说一下join()和detach()的使用技巧。
join及detach上述例子中已经用到了join和detach,以下对两者进行说明。 对于C++程序而言,你的main函数就是你的主线程,主线程在任何需要的时候都可以创建新的线程,当线程执行完毕时,自动终止线程;当进程结束时,所有线程都必须终止。所谓join就是主线程在调用join方法的位置等待子线程会合,会合之后执行下一步操作。所谓detach就是,主线程将不等待子线程的会合,自己直接结束生命,子线程未执行完也不报错,会自己在执行完毕后会退出。如果某个线程,不声明以上两者之一,但是在主线程结束之前又没有执行完毕,程序执行时会崩溃。--------------------- 作者:yucicheung 来源:CSDN 原文:https://blog.csdn.net/yucicheung/article/details/82466302 版权声明:本文为博主原创文章,转载请附上博文链接!
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
C++11多线程std::thread的简单使用
C++:线程(std::thread)
Inside DllMain
C++多线程入门(一)
Linux多线程——使用互斥量同步线程
Python线程5分钟完全解读
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服