多线程
线程:线程就是一个执行流(运行代码,处理数据)
线程概念:操作系统中使用pcb来描述一个程序的运行-PCB就是进程,Linux下以pcb模拟实现线程,Linux下的pcb实际是一个轻量级进程LWP。因为共用大部分进程资源,相较于传统进程更加轻量化
进程是资源分配的基本单位—因为程序运行时资源是分配给整个线程组(进程)的
线程是CPU调度的基本单位—因为Linux下pcb是线程
线程之间资源的独有与共享:
独有:栈,寄存器,信号屏蔽字,errno,线程ID,调度优先级
共享:虚拟地址空间(共享代码段和数据段),文件描述符表,信号处理方式,当前工作路径,用户ID、组ID
多线程任务处理的优缺点:
多线程共用大部分资源
线程间通信更加方便,除了进程间的方式之外还有更简单的就是全局数据/传参
创建/销毁一个线程的成本相较于进程更低
线程间的调度相较于进程更低
线程间缺乏访问控制,有些系统调用/异常针对的是整个进程,稳定性相较于进程更低
使用场景:shell这种对主程序稳定安全性要求更高的程序需要使用多进程
线程控制:
Linux下并没有提供线程的控制系统调用接口,因此大佬们封装了一套线程控制库函数
使用库函数实现创建的的线程我们称之为用户态线程,这个用户线程在内核中使用一个轻量级进程实现调度
POSIX线程库:
要是用这些函数库,必须要引入头文件
链接这些线程库函数时要使用编译命令“-lpthread”选项
线程创建:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
参数解析:
thread:用于获取线程ID,线程ID就是线程地址空间在整个虚拟地址空间中的首地址
attr:设置线程属性,通常置NULL
start_routine:线程的入口函数
arg:传递给线程函数的参数
返回值:0-成功 !0-创建失败-errno
线程中ID
tid 线程空间首地址
pcb->pid 轻量级进程ID
pcb->tgid 线程组ID,默认等于首线程ID
//体验每一个线程都是一个执行流
#include
#include
#include
void* thr_entry(void* arg){
while(1){
printf("i am commom thread---%s\n",(char*) arg);
sleep(1);
}
return NULL;
}
int main(){
pthread_t tid;
char *param="this is input param";
int ret=pthread_create(&tid,NULL,thr_entry,(void*)param);
if(ret!=0){
printf("pthread create error\n");
return -1;
}
printf("tid:%p\n",tid);
while(1){
printf("i am main thread---\n");
sleep(1);
}
return 0;
}
线程终止:
可以使用return来终止线程,但不能在main函数中return,因为退出的是进程,会导致所有线程退出
void pthread_exit(void *retval); 退出线程本身,谁调用就退出谁
retval:线程的退出返回值
int pthread_cancel(pthread_t thread); 取消其他线程,让其他线程退出
thread:要取消的线程ID
线程退出后,默认不会自动释放资源(保存自己的退出结果在线程独有的地址空间中),因此也会造成资源泄露
主线程退出,其他线程依然可以正常运行
//体验一个线程退出的几种方式
#include
#include
#include
void* thr_entry(void* arg){
sleep(5);
//线程终止
pthread_cancel((pthread_t)arg);
//pthread_exit("hello");
while(1){
printf("i am commom thread---%s\n",(char*) arg);
sleep(1);
}
return NULL;
}
int main(){
pthread_t mtid;
//获取自身线程ID
mtid= pthread_self();
pthread_t tid;
//线程创建
int ret=pthread_create(&tid,NULL,thr_entry,(void*)mtid);
if(ret!=0){
printf("pthread create error\n");
return -1;
}
//线程等待
void *retval;
pthread_join(tid,&retval);
printf("tid:%p retval:%s\n",tid,retval);
//取消线程
//pthread_cancel(tid);
while(1){
printf("i am main thread---\n");
sleep(1);
}
return 0;
}
线程等待:
等待线程退出,获取退出线程的返回结果,释放退出线程资源
前提:一个线程创建出来默认有一个属性—joinable
处于joinable属性的线程退出后,不会自动释放资源,需要其他线程等待才能释放资源
处于joinable属性的线程必须被等待
int pthread_join(pthread_t thread, void **retval);
功能:阻塞等待执行线程退出,通过retval获取返回值
线程分离:
将线程joinable属性修改为detach属性,处于detach属性的线程退出后会自动回收资源
并且这个线程不需要被等待,等待也毫无意义,因为线程退出返回值占用的空间已经被回收了
pthread_detach(pthread_t tid)
线程分离的适用场景:对线程的返回值不关心
线程分离可以在任意线程中实现