前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++ 线程操作

C++ 线程操作

作者头像
为为为什么
发布2023-03-19 10:04:47
3730
发布2023-03-19 10:04:47
举报
文章被收录于专栏:又见苍岚又见苍岚

线程也叫轻量级进程,通常一个进程包含若干个线程。线程可以利用进程所拥有的资源。 本文记录 C++ 操作线程的方法。

并发

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

并发的实现主要有两种方式:

  1. 多进程实现并发
  2. 单个进程,多个线程实现并发,就是一个主线程多个子线实现。

thread

C++ 11 之后添加了新的标准线程库 std::thread ,用于线程控制,std::thread<thread> 头文件中声明,因此使用 std::thread 时需要包含 在 <thread> 头文件。

std::thread 默认构造函数,创建一个空的 std::thread 执行对象。

代码语言:javascript
复制
#include<thread>
std::thread thread_object(callable)

一个可调用对象可以是以下三个中的任何一个:

  • 函数指针
  • 函数对象
  • lambda 表达式

创建线程

不带参的方式创建线程

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

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

通过类和对象创建线程

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

代码语言:javascript
复制
#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;
}

通过Lambda表达式创建线程

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

代码语言:javascript
复制
#include<iostream>
#include<thread>
using namespace std;
int main(){
	thread  t1([]{cout<<"子线程调用..."<<endl;});
	t1.join();
	cout<<"主线程..."<<endl;
}

带参的方式创建线程

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

代码语言:javascript
复制
#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;
}

当有多个参数时可以直接接在线程的构造函数参数中,他会在后台默默运行

如果测试时设置了断点发现测试日志没有成功输出,可能是子线程还没有开始运转,可以加个 while(1){;} 再观察结果。

智能指针的方式创建线程

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

代码语言:javascript
复制
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中去,子线程结束后,智能指针自动释放啦。
}

类的成员函数创建线程

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

代码语言:javascript
复制
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;
}

使用方法

线程运行函数

创建线程:调用 thread 类去调用一个线程的对象,添加处理函数作为线程的任务

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

子线程可能正在运行时主线程已经退出了,可能会报出异常退出的错误,这就需要将线程的调度整合起来。

join( )

可以利用 join 函数加入,汇合线程,阻塞主线程。添加以后等线程运行结束之后才运行主线程。

注意: 一个线程只能 join 一次,不能重复。

代码语言:javascript
复制
#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;
}

输出

代码语言:javascript
复制
子线程在运行。。。
主线程。。。

detach( )

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

代码语言:javascript
复制
#include<iostream>
#include<thread>
#include<windows.h>
using namespace std;
//线程处理函数
void print()
{
    Sleep(2000);//休眠2s
    cout << "子线程在运行..." << endl;
}
int main()
{
    //创建线程
    thread t1(print);
    t1.detach();//子线程与主线程分离
    cout << "主线程..." << endl;
    return 0;
}

输出

代码语言:javascript
复制
主线程...

joinable( )

joinable( ) 函数是一个布尔类型的函数,他会返回一个布尔值来表示当前的线程是否是可执行线程(能被 join 或者 detach)

因为相同的线程不能 join 两次,也不能 join 完再 detach, 同理也不能 detach, 所以 joinable 函数就是用来判断当前这个线程是否可以 join 的。

代码语言:javascript
复制
#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;
}

输出

代码语言:javascript
复制
子线程在运行。。。
主线程...
不能进行join

get_id()

获取当前线程 id

代码语言:javascript
复制
std::this_thread.get_id()

参考资料

文章链接: https://cloud.tencent.com/developer/article/2242007

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023年3月17日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 并发
  • thread
  • 创建线程
    • 不带参的方式创建线程
      • 通过类和对象创建线程
        • 通过Lambda表达式创建线程
          • 带参的方式创建线程
            • 智能指针的方式创建线程
              • 类的成员函数创建线程
              • 使用方法
                • 线程运行函数
                  • join( )
                    • detach( )
                      • joinable( )
                      • 参考资料
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档