【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;}