ToB企服应用市场:ToB评测及商务社交产业平台
标题:
【Linux】一文带你了解C++中的多线程及其底层逻辑(thread、join、封装线程
[打印本页]
作者:
鼠扑
时间:
2025-1-25 06:08
标题:
【Linux】一文带你了解C++中的多线程及其底层逻辑(thread、join、封装线程
绪论
每日鼓励:“不设限和自我肯定的心态:I can do all things。 — Stephen Curry”
绪论:
本章是线程的第三篇章,前两章带你了解了线程以及线程原生库中的操纵,本章主要结合前两章的根本,学习入门c++中的线程函数,了解其底层是什么,并且自己封装一个线程库来使用并巩固。
————————
早关注不迷路,话不多说安全带系好,发车啦(建议电脑观看)。
站在语言角度再理解pthread库
C++中的多线程
创建线程:thread
等候线程:join
#include<unistd.h>
#include<thread>
#include<iostream>
using namespace std;
void myrun()
{
while(true)
{
cout << "i am thread" << endl;
sleep(1);
}
}
int main()
{
thread t(myrun);
t.join();
return 0;
}
复制代码
其中使用到的c++中封装的线程函数 thread、join,他们在编译的时候纵然看起来没有使用到原生线程库,但同样要加-lpthread,由于c++的多线程本质上就是封装了Linux(或Windows)的多线程,所以同样要包括pthread库。
也就是说:c++的库中的函数本质是对pthread库中体系调用函数(pthread_create)的封装(C++11内部的多线程,本质就是对原生线程库的封装)
线程属性的局部存储
含线程代码中的全局变量,在多个线程中是共享的。
代码:
#include<iostream>
#include<unistd.h>
#include<cstdlib>
#include<string>
#include<pthread.h>
#include <thread>
using namespace std;
int g_val = 100;
void* ThreadRountine(void * args)
{
string name = static_cast<const char *>(args);
while(true)
{
sleep(1);
cout << name <<": g_val:" << g_val << " &g_val: " << &g_val << endl;
g_val--;
}
return nullptr;
}
int main()
{
pthread_t tid;
pthread_create(&tid,nullptr,ThreadRountine,(void*)"thread1");
while(true)
{
sleep(1);
cout << "main thread:"<<" g_val: " << g_val << " &g_val: " << &g_val << endl;
}
pthread_join(tid,nullptr);
}
复制代码
此处线程中举行了递减操纵,发现外部主线程中同样也减少了:也就说明他们是共享的资源!
__thread
线程的局部存储:当给全局变量前加上__thread编译选项,这样就能实现线程的局部存储,每个线程都有自己的该全局变量。
留意点:__thread只能针对内置类型
__thread int g_val = 100;
复制代码
上面的g_val就各自有一份了!
注:
线程中可以举行fork吗?虽然是可以在多线程程序中调用 fork(),但这种做法可能会导致程序的行为不稳定。尤其是如果你在多线程中使用 fork() 然后调用 exec() 来替换程序,可能会破坏多线程环境,由于 exec() 会终止全部线程。因此,除非非常必要,否则在多线程环境中使用 fork() 一般是不推荐的,特别是如果你计划举行进程替换。
模仿实现封装c++中的线程:
根据之前所知:c++的线程库底层本质就是封装了原始线程库的,所以自己也能通过面向对象的封装来自己实现,从而让自己更加了解
(很多细节请看解释)
thread.hpp:
#pragma once
#include<iostream>
#include<string>
#include<functional>
#include<pthread.h>
using namespace std;
//typedef function<void()> func_t
using func_t = function<void()>;//返回值void 参数为空;
class Thread
{
public:
Thread(func_t func,const string& name)
:_tid(0),_name(name),_isrunning(false),_func(func)
{}
//因为在类内的函数默认是有this指针的这样就会导致pthread_create的threadrotine的类型不匹配而导致的无法传参
//所以解决方法就是改成静态函数,但此时又不能使用成员变量了
//所哟把参数args改成this传递进来!
static void *ThreadRotine(void* args)
{
Thread *ts = static_cast<Thread*>(args);//安全的类型转换
ts->_func();//执行函数
return nullptr;
}
bool Start()
{
int n = pthread_create(&_tid,nullptr,ThreadRotine,this);//创建线程
if(n == 0)
{
_isrunning = true;
return true;
}
else return false;
}
string Threadname()
{
return _name;
}
bool Join()
{
if(!_isrunning) return true;
int n = pthread_join(_tid,nullptr);//等待线程
if(n==0)
{
_isrunning = false;
return true;
}
return false;
}
bool Isrunning()
{
return _isrunning;
}
~Thread()
{}
private:
string _name;
func_t _func;
pthread_t _tid;//创建自动形成
bool _isrunning;
};
复制代码
main.cpp:
#include<iostream>
#include<thread>
#include<cstdlib>
#include "Thread.hpp"
#include<unistd.h>
#include<vector>
using namespace std;
string GetThreadname()
{
static int number = 1;//本质就是全局变量
char name[64];
snprintf(name,sizeof(name),"thread-%d",number++);
return name;
}
void Print()
{
while(true)
{
cout << "hello Linux"" << endl;
sleep(1);
}
}
int main()
{
const int num = 5;
vector<Thread> threads;
for(int i = 0 ; i < num ;i++)
{
threads.push_back(Thread(Print,GetThreadname()));
}
//此时并没有启动线程
for(auto &t : threads)
{
cout << t.Threadname() << " is,running:" << t.Isrunning() <<endl;//打印线程名称即运行状态
}
sleep(5);
for(auto &t:threads)
{
t.Start();
}
//启动线程后
for(auto &t : threads)
{
cout << t.Threadname() << " is,running:" << t.Isrunning() <<endl;
}
for(auto &t : threads)
{
t.Join();
}
// Thread t(Print,GetThreadname());
// cout << "is thread running?: " << t.Isrunning() << endl;
// t.Start();
// cout << "is thread running?: " << t.Isrunning() << endl;
// t.Join();
return 0;
}
复制代码
线程从未启动->启动->执行所对应的任务:
参加模板:写成能传参自界说函数和参数
//thread.hpp
#pragma once
#include<iostream>
#include<string>
#include<functional>
#include<pthread.h>
using namespace std;
//注意!!
//此处的修改,因为带有模板所以后面用该类型变成fun_t<T>
template<class T>
using func_t = function<void(T)>;//返回值void 参数为;
//加上模板,这个类型是给传进来的参数数据data的!
template<class T>
class Thread
{
public:
Thread(T data,func_t<T> func,const string& name)//此处从fun_t -> fun_t<T>
:_tid(0),_name(name),_isrunning(false),_func(func),_data(data)
{}
//因为在类内的函数默认是有this指针的这样就会导致pthread_create的threadrotine的类型不匹配而导致的无法传参
//所以解决方法就是改成静态函数,但此时又不能使用成员变量了,所哟把参数args改成this传递进来!
static void *ThreadRotine(void* args)
{
Thread *ts = static_cast<Thread*>(args);
ts->_func(ts->_data);
return nullptr;
}
//...和上面一样就省略了
private:
string _name;
func_t<T> _func;//此处从fun_t -> fun_t<T>
pthread_t _tid;//创建自动形成
bool _isrunning;
T _data;
};
// ---------------------------------
//main.cpp
#include<iostream>
#include<thread>
#include<cstdlib>
#include"Thread.hpp"
#include<unistd.h>
#include<vector>
using namespace std;
string GetThreadname()
{
static int number = 1;//本质就是全局变量
char name[64];
snprintf(name,sizeof(name),"thread-%d",number++);
return name;
}
void Print(int num)
{
while(num)
{
cout << "hello Linux: " << num-- << endl;
sleep(1);
}
}
int main()
{
Thread<int> t(10,Print,GetThreadname());
t.Start();
t.Join();
return 0;
}
复制代码
本章完。预知后事如何,暂听下回分解。
如果有任何题目欢迎讨论哈!
如果觉得这篇文章对你有所帮助的话点点赞吧!
连续更新大量Linux细致内容,早关注不迷路。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4