【Linux】线程控制(二)

【Linux】线程控制(二)

文章目录

背景

Linux中没有真正的线程概念,而是复用进程数据结构和管理算法,用进程模拟线程

只有轻量级进程,不会提供线程的调用接口,而是提供轻量级进程的系统调用接口

但是我们用户需要线程调用,所以有pthread库帮我们封装了轻量级进程调用接口,我们可以直接使用线程接口

  • 每个linux平台自带pthread库,
  • 编写多线程代码需要pthread库

线程接口

在这里插入图片描述


每个线程都有自己的ID,
⭐pthread_create不是系统调用,需链接 -pthread

🚩进程控制

快速使用一下

#include<iostream>#include<pthread.h>#include<unistd.h> using namespace std;void*threadRoutine(void*args){constchar* str=(constchar*)args; cout<<str<<endl;int cnt=5;while(cnt--){ cout<<"thread id :"<<pthread_self()<<endl;sleep(1);}}intmain(){pthread_t tid; cout<<tid<<endl;pthread_create(&tid,nullptr,*threadRoutine,(void*)"thread 1"); cout<<tid<<endl;pthread_join(tid,nullptr);return0;}
在这里插入图片描述

刚开始tid没有初始化,主线程要最后一个退出,等待子线程

线程等待默认是阻塞的,为什么不考虑异常呢?
因为单个线程如果异常,整个进程都崩溃了

int g_val=100;void*threadRoutine(void* args){constchar* str=(constchar*)args;int cnt=5;while(cnt--){printf("%s pid: %d, g_val: %d, &g_val: 0x%p \n",str,getpid(),g_val,&g_val);sleep(1); g_val++;}//pthread_exit(100) //exit(100); //不能用exit,直接把整个进程退出了return(void*)100;//退出线程}intmain(){pthread_t tid;pthread_create(&tid,nullptr,*threadRoutine,(void*)"thread 1");int cnt=5;while(cnt--){printf("main thread %d, g_val: %d, &g_val: 0x%p , create a new thread: %p \n",getpid(),g_val,&g_val, tid);sleep(1); g_val++;}sleep(2);void* set;pthread_join(tid,&set); cout<<"new thread quit success"<<(longlongint)set<<endl;return0;}
ps -aL查看所有线程
while :; do ps -aL; sleep 1;done;监控
在这里插入图片描述


可以看到两个mythread,进程pid相同,LWP(light weight process轻量化进程)不同

  • LWP在内核看来就是线程

线程ID有两种:一种是内核视角LWP,另一种线程视角pthread_t

在这里插入图片描述


两个不同的执行流,共享相同的全局变量,也可以调用相同的函数,这里发生数据冲突了,后面会讲

所以,用户级线程(线程库控制)加上内核LWP才构成Linux线程,Linux也有内核级线程
用户级执行流:LWP=1:1

在这里插入图片描述

线程计算1-100

class Reques t { public:Request(int begin,int end,const string& threadname):_begin(begin),_end(end),_threadname(threadname){} public:int _begin;int _end; string _threadname;}; class Reponse { public:Reponse(int result,int exitcode):_result(result),_exitcode(exitcode){} public:int _result;//计算结果int _exitcode;//计算结果是否可靠};void*sumRoutine(void* args)// 线程的参数和返回值,不仅仅可以传递一般参数,还可以传递自定义对象{ Request* rq=static_cast<Request*>(args);//(Request*)args; Reponse* rsp=new Reponse(0,0);if(rq->_begin>rq->_end){ rsp->_exitcode=-1;}else{for(int i=rq->_begin;i<=rq->_end;i++){ rsp->_result+=i;}} delete rq;return rsp;}intmain(){pthread_t tid; Request *rq=new Request(1,100,"thread 1");pthread_create(&tid,nullptr,*sumRoutine,rq);void* set;pthread_join(tid,&set); Reponse *rsp=static_cast<Reponse*>(set); cout<<"rsp -> _result: "<<rsp->_result<<"rsp ->_exitcode: "<<rsp->_exitcode <<endl; delete rsp;return0;}
在这里插入图片描述

🚩线程库

线程的概念是库给我们维护的,线程库中有clone回调函数将执行流给进程PCB,共享父进程资源,线程库维护线程概念,不用维护执行流,线程库注定要维护多个线程属性集合,先描述再组织

线程库要不要加载到内存?
要,加载到共享区,等于动态库

在这里插入图片描述
在这里插入图片描述

c++11多线程

C++11也支持多线程了,已经帮我们封装好了,直接用就行

voidthreadrun(){while(true){ cout <<"I am a new thead for C++"<< endl;sleep(1);}}intmain(){ thread t1(threadrun); t1.join();return0;}

Read more

使用现代C++构建高效日志系统的分步指南

使用现代C++构建高效日志系统的分步指南

使用现代C++构建高效日志系统的分步指南 * 1. 确定日志系统的需求和目标 * 2. 设计日志系统的架构 * 3. 实现阶段 * 3.1 实现日志管理器(LogManager) * 3.2 实现日志记录器(Logger) * 3.3 实现日志格式化器(Formatter) * 3.4 实现日志输出器(Outputter) * 3.5 实现日志文件轮转 * 3.6 实现异常处理 * 3.7 实现性能优化 * 4. 测试和验证 * 5. 文档编写 * 6. 总结 在软件开发中,日志系统扮演着关键角色,帮助开发者记录程序运行状态、调试问题以及监控系统性能。使用现代C++构建一个高效且灵活的日志系统,不仅可以提升开发效率,还能增强程序的可维护性和可靠性。以下是构建这样一个日志系统的详细分步指南: 1. 确定日志系统的需求和目标

By Ne0inhk
【C++动态规划 贪心】3180. 执行操作可获得的最大总奖励 I|1848

【C++动态规划 贪心】3180. 执行操作可获得的最大总奖励 I|1848

本文涉及知识点 C++贪心 C++动态规划 LeetCode3180. 执行操作可获得的最大总奖励 I 给你一个整数数组 rewardValues,长度为 n,代表奖励的值。 最初,你的总奖励 x 为 0,所有下标都是 未标记 的。你可以执行以下操作 任意次 : 从区间 [0, n - 1] 中选择一个 未标记 的下标 i。 如果 rewardValues[i] 大于 你当前的总奖励 x,则将 rewardValues[i] 加到 x 上(即 x = x + rewardValues[i]),并

By Ne0inhk
【探寻C++之旅】C++ 智能指针完全指南:从原理到实战,彻底告别内存泄漏

【探寻C++之旅】C++ 智能指针完全指南:从原理到实战,彻底告别内存泄漏

前言 作为 C++ 开发者,你是否曾因以下场景头疼不已?函数中new了数组,却因异常抛出导致后续delete没执行,排查半天定位到内存泄漏;多模块共享一块内存,不知道该由谁负责释放,最后要么重复释放崩溃,要么漏释放泄漏;用了auto_ptr后,拷贝对象导致原对象 “悬空”,访问时直接崩溃却找不到原因。 如果你有过这些经历,那智能指针一定是你必须掌握的现代 C++ 工具。它基于 RAII 思想,自动管理动态资源,让你无需手动delete,从根源上减少内存泄漏风险。今天,我们就从 “为什么需要智能指针” 到 “不同智能指针的实战场景”,带你系统掌握这一核心特性。 请君浏览 * 前言 * 一、智能指针的诞生:解决手动管理内存的 “千古难题” * 1.1 一个典型的内存泄露场景 * 1.2 智能指针的核心:RAII 思想 * 二、C++ 标准库智能指针:

By Ne0inhk
C++:用红黑树封装map与set-2

C++:用红黑树封装map与set-2

文章目录 * 前言 * 一、红黑树封装map与set中const迭代器 * 1. 框架的搭建 * 2. set实现const迭代器 * 3. map实现const迭代器 * 二、operator[ ] * 1. operator[ ]要达成的样子 * 2. insert的改变 * 三. 解决insert里set中的问题 * 四. 解决map中的operator[ ] * 总结用红黑树封装map与set代码 前言 前面我们map与set封装的已经差不多了,接下来还有一些细节需要处理,本片博客主要解决const迭代器以及引发的一些其他问题~😘😘 总后的总结完整的源码封装的源码附上~🥰🥰 想看前面的封装是怎么实现的戳这里哦宝宝~❤️❤️ <( ̄︶ ̄)↗[GO!] 一、红黑树封装map与set中const迭代器 1. 框架的搭建 首先,和以前一样,要写出const迭代器,和以前一样通过控制三个模板参数,从而控制operator*以及operator->的返回值,从而控制普通迭代器与const迭代器。 改变模板参数,控

By Ne0inhk