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

进程与线程

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

并发

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

C++中创建线程的方式

  • 头文件 #include
  • 创建线程:调用 thread 类去调用一个线程的对象
#include<iostream>
#include<thread>
using namespace std;
void print(){
    
    
	cout<<"子线程在运行。。。"<<endl;
}
int main(){
    
    
	//创建线程
	thread t1(print);//print为线程处理函数
	cout<<"主线程。。。"<<endl;
	return 0;
}

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

join( )函数

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

#include<iostream>
#include<thread>
#include<windows.h>
using namespace std;
//线程处理函数
void print(){
    
    
	Sleep(2000);//休眠2s
	cout<<"子线程在运行..."<<endl;
}
int main(){
    
    
	//创建线程
	thread t1(print);
	t1.join();//阻塞 ,添加以后等线程运行结束之后才运行主线程
	cout<<"主线程..."<<endl;
	return 0;
}
//运行结果:
/*
子线程在运行。。。
主线程。。。
*/

detach( )函数

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

void print(){
    
    
	Sleep(2000);//休眠2s
	cout<<"子线程在运行..."<<endl;
}
int main(){
    
    
	//创建线程
	thread t1(print);
	t1.detach();//子线程与主线程分离
	cout<<"主线程..."<<endl;
	return 0;
}
//运行结果:
/*
主线程...
*/

joinable( )函数

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

#include<iostream>
#include<thread>
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
*/

创建线程的方式

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

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

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

#include<iostream>
#include<thread>
using namespace std;
void print(){
    
    
	cout<<"子线程在运行。。。"<<endl;
}
int main(){
    
    
	//创建线程
	thread t1(print);//print为线程处理函数
	cout<<"主线程。。。"<<endl;
	return 0;
}
/*
子线程在运行。。。
主线程。。。
*/

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

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

#include<iostream>
#include<thread>
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;
}

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

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

#include<iostream>
#include<thread>
using namespace std;
int main(){
    
    
	thread  t1([]{
    
    cout<<"子线程调用..."<<endl;});
	t1.join();
	cout<<"主线程..."<<endl;
}
//运行结果
/*
子线程调用...
主线程...
*/

4.带参的方式创建线程

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

#include<iostream>
#include<thread>
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
主线程...
*/

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
*/

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
*/

猜你喜欢

转载自blog.csdn.net/mitongxue/article/details/127896373