多线程 —— 线程控制

目录

    • 线程控制
      • 1 线程创建
      • 2 线程等待
      • 3 线程终止
      • 4 线程分离
    • pthread_t id && LWP

线程控制

1 线程创建

功能:创建一个新的线程
原型
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)
(void*), void *arg);
参数
thread:返回线程ID
attr:设置线程的属性,attr为NULL表示使用默认属性
start_routine:是个函数地址,线程启动后要执行的函数
arg:传给线程启动函数的参数
返回值:成功返回0;失败返回错误码
#include 
#include 
#include 

void *thread_run(void *args){
  while(1){
    //printf("我是新线程[%s],我创建的线程ID是:%lu\n", (const char*)args, pthread_self());
    sleep(1);
  }
  
}
int main(){
   
  pthread_t tid[5];
  int i;
  for(i = 0; i < 5; i++){
    pthread_create(tid+i, NULL, thread_run, (void *)"new thread");
  }

  while(1){

    printf("我是主线程,我的thread ID:%lu\n", pthread_self());
    printf("##############################begin#########################\n");
    for(i = 0; i < 5; i++){
      printf("我创建的线程[%d]是:%lu\n", i, tid[i]);
    }
    printf("###############################end##########################\n");
    sleep(1);
  }
}

多线程 —— 线程控制_第1张图片

2 线程等待

一般而言,线程也是需要等待的,如果不等待,可能会导致类似于“僵尸进程”的问题!

用下面这个函数实现等待

多线程 —— 线程控制_第2张图片

举个例子:

下面这个程序会因为单个线程的野指针问题而造成所有线程崩溃

#include 
#include 
#include 

void *thread_run(void *args){
  int num = *(int*)args;
  while(1){
    //printf("我是新线程[%s],我创建的线程ID是:%lu\n", (const char*)args, pthread_self());
    sleep(1);
    //野指针问题,测试一个线程崩整个进程则崩的问题
    if(num == 3){
      printf("thread number: %d quit\n", num);
      int *p = NULL;
      *p = 1000;
    }
  }
  
}

#define NUM 5

int main(){
   
  pthread_t tid[NUM];
  int i;
  for(i = 0; i < NUM; i++){
    pthread_create(tid+i, NULL, thread_run, (void *)&i);
    sleep(1);
  }

  while(1){

    printf("我是主线程,我的thread ID:%lu\n", pthread_self());
    printf("##############################begin#########################\n");
    for(i = 0; i < NUM; i++){
      printf("我创建的线程[%d]是:%lu\n", i, tid[i]);
    }
    printf("###############################end##########################\n");
    sleep(1);
  }
  return 0;
}

运行结果

image-20230529211559468

  • 使用pthread_join进行线程等待
#include 
#include 
#include 

void *thread_run(void *args){
  int num = *(int*)args;
  while(1){
    printf("我是新线程[%s],我创建的线程ID是:%lu\n", (const char*)args, pthread_self());
    sleep(1);
    break;
    //野指针问题,测试一个线程崩整个进程则崩的问题
    //if(num == 3){
    //  printf("thread number: %d quit\n", num);
    //  int *p = NULL;
    //  *p = 1000;
    //}
  }
  //退出异常,不需要处理
  //这里的返回值也可以是其他变量,不一定为int型,但不能是临时的
  return (void*)111;  
}

#define NUM 1

int main(){
   
  pthread_t tid[NUM];
  int i;
  for(i = 0; i < NUM; i++){
    pthread_create(tid+i, NULL, thread_run, (void *)&i);
    sleep(1);
  }

  //void* 32.4 64.8, 指针变量。本身就可以充当某种容器保存数据
  void *status = NULL;
  //退出信息
  pthread_join(tid[0], &status);

  printf("ret: %d\n", (int)status);
//while(1){

  //  printf("我是主线程,我的thread ID:%lu\n", pthread_self());
  //  printf("##############################begin#########################\n");
  //  for(i = 0; i < NUM; i++){
  //    printf("我创建的线程[%d]是:%lu\n", i, tid[i]);
  //  }
  //  printf("###############################end##########################\n");
  //  sleep(1);
  //}
  return 0;
}

image-20230529213110071

多线程 —— 线程控制_第3张图片

线程出异常,pthread_join不需要处理,这是进程的问题

3 线程终止

  1. 函数中return

    image-20230529214306808

  2. pthread_exit

    新线程通过pthread_exit终止自己(vs exit是终止进程,只想终止一个线程时不要调用)

    image-20230529214615101

    image-20230529214546540

  3. pthread_cancel

    直接发起一个请求给目标进程,即取消目标线程

    #include 
    #include 
    #include 
    
    void *thread_run(void *args){
      int num = *(int*)args;
      while(1){
        printf("我是新线程[%s],我创建的线程ID是:%lu\n", (const char*)args, pthread_self());
        sleep(2);
        //break;
        //野指针问题,测试一个线程崩整个进程则崩的问题
        //if(num == 3){
        //  printf("thread number: %d quit\n", num);
        //  int *p = NULL;
        //  *p = 1000;
        //}
      }
      //线程出异常不需要处理
      //这里的返回值可以是其他变量,并非只能int,但不能是临时变量
      
      //pthread_exit((void*)123);
      //return (void*)111;  
    }
    
    #define NUM 1
    
    int main(){
       
      pthread_t tid[NUM];
      int i;
      for(i = 0; i < NUM; i++){
        pthread_create(tid+i, NULL, thread_run, (void *)&i);
        sleep(1);
      }
      printf("wait sub thread...\n");
      sleep(5);
      printf("cancel sub thread....\n");
      pthread_cancel(tid[0]);
    
      //void* 32.4 64.8, 指针变量。本身就可以充当某种容器保存数据
      void *status = NULL;
      pthread_join(tid[0], &status);
    
      printf("ret: %d\n", (int)status);
      sleep(3);
    //while(1){
    
      //  printf("我是主线程,我的thread ID:%lu\n", pthread_self());
      //  printf("##############################begin#########################\n");
      //  for(i = 0; i < NUM; i++){
      //    printf("我创建的线程[%d]是:%lu\n", i, tid[i]);
      //  }
      //  printf("###############################end##########################\n");
      //  sleep(1);
      //}
      return 0;
    }
    

    运行结果,可以发现,取消线程,退出码为-1

    多线程 —— 线程控制_第4张图片

    可以用其他线程取消主线程,但此时可能会造成僵尸进程问题,此时里面还可能有子线程在运行。

4 线程分离

image-20230529221652719

分离之后的线程不需要被join,运行完毕之后,会自动释放Z,pcb。
一般都是自己分离自己,也可以主线程分离新线程。
一个线程被设置分离之后,就不能再被join了。

pthread_t id && LWP

我们查看到的线程id是pthread库的线程id,不是Linux内核中的LWP,pthread库的线程id是一个内存地址!

你可能感兴趣的:(Linux,linux)