Linux【线程控制】

多线程

线程:线程就是一个执行流(运行代码,处理数据)
线程概念:操作系统中使用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)
线程分离的适用场景:对线程的返回值不关心
线程分离可以在任意线程中实现

你可能感兴趣的:(Linux【线程控制】)