目录
1.多线程概念
多线程是一个进程运行时,多个线程交替并行在多个cpu执行的过程,可以提高代码执行效率。进程是操作调度的最小单位,线程是进程的最小执行单位。
在进程阶段,我们可以通过创建子进程,然后通过进程程序替换实现同时执行多个任务,现在只使用一个进程创建出多个线程就可以达到相同的效果,且线程间切换效率更高。
1.1主线程
之前的程序只用到一个进程,也可以称之为主线程(LWP),即main函数执行流。一般使用pid表示线程id,使用tgid表示进程组id,主线程的线程id等于进程组id。如果我们创建出多个线程,则执行main函数的线程就是主线程,其它线程我们称之为工作线程(LWF),每个工作线程都有自己的pid,一个进程的所有线程都享有一个tgid。
1.2 线程内部原理图
1.3多线程的共享与独有
以前我们了解到一个进程有一个进程控制块(pcb),一个pcb就是一个task_struct结构体,现在我们再细化一下,创建线程时,操作系统会在pcb中加入线程的task_struct结构体。它们共享一个进程虚拟地址空间,线程之间很多资源都是共享的,这也是线程切换效率高的原因。但是不同的线程需要执行不同的代码,这也叫就意味着它们需要有部分资源是独立的,这部分资源就放在进程虚拟地址空间的共享区中。它包括调用栈,寄存器,线程id,errno,信号屏蔽字,调度优先级等。
1.4 多线程优缺点
优点
1.多线程的程序,拥有多个执行流,合理使用,可以提高程序的运行效率。
2.多线程程序比进程切换速度快,付出的代价小(对于共享的数据,比如全局变量可以不切换直接使用)
3.对计算密集型数据,可以进行拆分,让不同线程执行不一样的事情。
4.对IO密集型的程序,可以进行拆分,让不同的线程执行不同的IO操作,避免了串行操作,提高了程序运行效率。
缺点
1.编写代码难度更高。
2.代码稳定性要求更高,一个线程崩溃会导致整个进程崩溃
3.缺乏访问控制,程序会产生二义性结果
4.一个线程崩溃,可能会导致整个进程退出
2线程控制
2.1线程创建
2.1.1接口
int pthread_create(pthread_t *thread,const pthread_attr_t,void*(*start_routine)(void*),void *arg); //参数 thread:获取线程标识符(地址),本质上就是线程独有空间的首地址。 attr:线程的属性信息,一般填写NULL,采用默认的线程属性 //属性信息当中比较关心的:调用栈大小,分离属性,调度策略,时间片轮转,调度优先级等 start_routine:函数指针,线程执行的入口函数 arg:给线程入口函数传递参数; 返回值: 成功:0 失败<0
作用:创建一个线程
2.1.2代码演示
#include<stdio.h> #include<unistd.h> #include<pthread.h> void* mythread(void* arg){ printf("i am workthread!\n"); } int main(){ //创建线程 pthread_t tid; int ret= pthread_create(&tid,NULL,mythread,NULL); if(ret<0){ perror("pthread_create"); return 0; } sleep(5); return 0; }
2.2线程终止
2.2.1接口
void pthread_exit(void *retval); //参数 retval:线程退出时,传递给等待线程的退出信息
作用:谁调用谁退出
int pthread_cancel(pthread_t thread); thread:被终止的线程标识符
作用:终止一个线程,参数传递线程标识符意味着线程可以终止非自己的线程
2.2.2代码演示
#include<stdio.h> #include<unistd.h> #include<pthread.h> void* mythread(void* arg){ while(1){ printf("i am workthread!\n"); //pthread_exit(NULL); } } int main(){ //创建线程 pthread_t tid; int ret= pthread_create(&tid,NULL,mythread,NULL); if(ret<0){ perror("pthread_create"); return 0; } sleep(1); pthread_cancel(tid); /// pthred_cancel() sleep(30); return 0; }
2.2.3线程的僵尸状态模拟
#include<stdio.h> #include<unistd.h> #include<pthread.h> void* mythread(void* arg){ while(1){ printf("i am workthread!\n"); } } int main(){ //创建线程 pthread_t tid; int ret= pthread_create(&tid,NULL,mythread,NULL); if(ret<0){ perror("pthread_create"); return 0; } pthread_cancel(pthread_self()); while(1){ sleep(100); } return 0; }
2.3线程等待
2.3.1接口
线程在创建出来时,默认属性是joinable属性,退出的时候,依赖其它线程来回收资源(主要是退出线程使用到的共享区的空间)
int pthread_join(pthread_t thread,void ** retval); trhread:线程标识符 retval:退出线程的退出信息 第一种:线程入口函数代码执行完毕,线程退出的,就是入口函数返回值 第二种:pthread
2.3.2代码演示
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
void* mythread(void* arg){
printf("i am workthread!\n");
}
int main(){
//创建线程
pthread_t tid;
int ret= pthread_create(&tid,NULL,mythread,NULL);
if(ret<0){
perror("pthread_create");
return 0;
}
pthread_join(tid,NULL);
return 0;
}
2.4线程分离
2.3.1接口
默认状态需要回收资源,设置分离属性就不用手动回收资源,操作系统自动进行回收。
int pthrerad_detach(pthread_t thread thread); thread:设置分离属性的线程标识符
2.3.2代码演示
void* mythread(void* arg){
pthred_detach(pthread_self());
printf("i am work thread\n");
}