• C++线程创建的方式和使用


    进程与线程

    • 进程
      简单的可以认为是一个程序执行的过程。进程就是活跃的程序,在内存中运行,占用系统的资源。
    • 线程
      线程也叫轻量级进程,通常一个进程包含若干个线程。线程可以利用进程所拥有的资源。在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,比如我们在利用微信聊天的同时,也可以和别人文字聊天。

    并发

    两个或者多个独立的活动同时进行的现象称为并发。并发可以简单的认为,可以理解成多个应用程序同时运行。在单核CPU中,并发实际上是一种假象,进程之间实际上是按照一定的分配算法轮流使用CPU。
    并发的实现主要有两种方式:
    1.多进程实现并发
    2.单个进程,多个线程实现并发,就是一个主线程多个子线实现。

    C++中创建线程的方式

    • 头文件 #include
    • 创建线程:调用 thread 类去调用一个线程的对象
    #include
    #include
    using namespace std;
    void print(){
    	cout<<"子线程在运行。。。"<<endl;
    }
    int main(){
    	//创建线程
    	thread t1(print);//print为线程处理函数
    	cout<<"主线程。。。"<<endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    运行结果:
    在这里插入图片描述
    可以看到,主线程和子线程的运行顺序是不一样的,在其他的编译器中,可能不会出现“子线程在运行。。。”的语句。

    join( )函数

    可以利用 join 函数加入,汇合线程,阻塞主线程。添加以后等线程运行结束之后才运行主线程。注意 一个线程只能join一次,不能重复。

    #include
    #include
    #include
    using namespace std;
    //线程处理函数
    void print(){
    	Sleep(2000);//休眠2s
    	cout<<"子线程在运行..."<<endl;
    }
    int main(){
    	//创建线程
    	thread t1(print);
    	t1.join();//阻塞 ,添加以后等线程运行结束之后才运行主线程
    	cout<<"主线程..."<<endl;
    	return 0;
    }
    //运行结果:
    /*
    子线程在运行。。。
    主线程。。。
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    detach( )函数

    detach( ) 函数用于打破主线程和子线程之间的依赖关系,将子线程和主线程之间进行分离,不影响。
    detach后,就不能再join

    void print(){
    	Sleep(2000);//休眠2s
    	cout<<"子线程在运行..."<<endl;
    }
    int main(){
    	//创建线程
    	thread t1(print);
    	t1.detach();//子线程与主线程分离
    	cout<<"主线程..."<<endl;
    	return 0;
    }
    //运行结果:
    /*
    主线程...
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    joinable( )函数

    joinable( ) 函数是一个布尔类型的函数,他会返回一个布尔值来表示当前的线程是否是可执行线程(能被join或者detach),因为相同的线程不能join两次,也不能join完再detach,同理也不能detach,所以joinable函数就是用来判断当前这个线程是否可以joinable的。

    #include
    #include
    using namespace std;
    void print(){
    	cout<<"子线程在运行。。。"<<endl;
    }
    int main(){
    	thread t1(print);
    	t1.join();
    	cout<<"主线程..."<<endl;
    	if(t1.joinable())
    		cout<<"能join"<<endl;
    	else
    		cout<<"不能进行join"<<endl;
    	return 0;
    }
    //运行结果
    /*
    子线程在运行。。。
    主线程...
    不能进行join
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    创建线程的方式

    创建线程的方式根据线程处理函数的不同,一共可以分成6种。

    1.不带参的方式创建线程

    不带参数的普通函数作为线程处理函数。

    #include
    #include
    using namespace std;
    void print(){
    	cout<<"子线程在运行。。。"<<endl;
    }
    int main(){
    	//创建线程
    	thread t1(print);//print为线程处理函数
    	cout<<"主线程。。。"<<endl;
    	return 0;
    }
    /*
    子线程在运行。。。
    主线程。。。
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.通过类和对象创建线程

    利用类中的仿函数作为线程处理函数。

    #include
    #include
    using namespace std;
    class A{
    	//STL 仿函数 类名模仿函数的行为
    	void operator()(){
    		cout<<"子线程..."<<endl;
    	}
    };
    int main(){
    	//正常写法1  对象充当线程处理函数
    	A a;
    	thread t1(a);
    	t1.join();
    	
    	//写法2
    //	thread t1((A()));
    //	t1.join();
    	
    	cout<<"主线程..."<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3.通过Lambda表达式创建线程

    Lambda表达式简单地说,就是将函数定义和调用放在一处实现。

    #include
    #include
    using namespace std;
    int main(){
    	thread  t1([]{cout<<"子线程调用..."<<endl;});
    	t1.join();
    	cout<<"主线程..."<<endl;
    }
    //运行结果
    /*
    子线程调用...
    主线程...
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4.带参的方式创建线程

    将带参数的函数作为线程处理函数。

    #include
    #include
    using namespace std;
    void p1(int &n){
    	cout<<"子线程"<<n<<endl;
    	n++;
    }
    int main(){
    	int n=0;
    	thread t3(p1,std::ref(n));//ref用于包装引用传值
    	t3.join();
    	thread t31(p1,std::ref(n));
    	t31.join();
    	cout<<"主线程..."<<endl;
    }
    /*
    子线程0
    子线程1
    主线程...
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    5.智能指针的方式创建线程

    就是以智能指针为参数的函数作为线程处理函数

    void p2(unique_ptr<int> ptr){
    	cout<<"子线程:"<<ptr.get()<<endl;
    	cout<<"子线程id: "<<this_thread::get_id()<<endl;//get_id函数获取线程id
    }
    
    int main(){
    	//智能指针为参数的线程处理函数
    	int *p=new int(12);
    	cout<<*p<<endl;//12
    	unique_ptr<int> ptr(new int(1000));
    	cout<<"主线程:"<<ptr.get()<<endl;//ptr.get() 获取智能指针的地址
    	thread t4(p2,move(ptr));
    	t4.join();
    	cout<<"主线程id: "<<this_thread::get_id()<<endl;
    	cout<<"主线程..."<<ptr.get()<<endl;//0000000 因为上面的语句将智能指针移动到p3中去,子线程结束后,智能指针自动释放啦。
    }
    /*
    12
    主线程:0x2b630bb1760
    子线程:0x2b630bb1760
    子线程id: 2
    主线程id: 1
    主线程...000000000
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    6.类的成员函数创建线程

    将类的成员函数作为线程处理函数

    class B{
    public:
    	void p3(int &num){
    		num=1100;
    		cout<<"子线程id:"<<this_thread::get_id()<<endl;
    	}
    };
    int main(){
    	//类的成员函数充当线程处理函数
    	B b;
    	int num=10;
    	//需要告诉是哪一个对象的成员函数
    	thread t5(&B::p3,b,ref(num));//注意创建thread类对象的方式
    	t5.join();
    	cout<<"主线程id: "<<this_thread::get_id()<<endl;
    }
    /*
    子线程id:2
    主线程id: 1
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    富文本编辑器——UEditor的使用——基础积累
    正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-1.3
    数据结构之-【排序】
    c# .net 树莓派/香橙派用到物联网包Iot.Device.bindings 支持设备说明文档
    数据结构代码实现快速排序
    《每日一题》NO.46:何为WAT/CP/FT?
    mysql5.7免安装教程,配置my.ini详解,安装卸载mysql服务,开启远程登录,修改mysql密码
    Pr:与 Ps、Ae、Au 的协同编辑
    Git 作用&&操作
    【DB运营管理/开发解决方案】上海道宁为您提供提高工作便利性的集成开发工具——Orange
  • 原文地址:https://blog.csdn.net/mitongxue/article/details/127896373