多线程的创建、等待、终止与分离

4 篇文章 0 订阅
本文详细介绍了在Linux中使用pthread库创建线程的基本步骤,包括线程ID的理解、线程创建、线程等待与终止的最佳实践,以及线程分离与用户线程管理。通过实例展示了如何创建多个线程,处理线程间的交互和资源清理,确保内存有效管理和线程安全。
摘要由CSDN通过智能技术生成

一、创建一个新的线程

1.头文件:<pthread.h>
2.函数:pthread_create(pthread_t *thread,const pyhread_attr_t *attr,void *(start_routine) (void ),void *arg);

名称意义
pthread_t相当于无符号长整型
*thread线程的ID
const pyhread_attr_t *attr线程的属性,一半不管,默认
void *(start_routine) (void )线程例程,实际上相当于创建线程的入口函数,本质是一个回调函数
void *arg函数的参数,有则传,没有设置为NULL
3.执行新的线程,主进程仍然继续执行
makefile文件:
mythread:mythread.c
	gcc -o $@ $^ -lpthread  #引的是pthread这个库
.PHONY:clean
clean:
	rm -f mythread

mythread文件:

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
void *Routine(void *arg)
{
  char *msg = (char*)arg;
  while(1)
  {
    printf("%s\n",msg);
    sleep(1);
  }
}

int main()
{
pthread_t tid;
  //创建线程
  pthread_create(&tid,NULL,Routine,(void*)"thread 1"); //传thread 1参数

  while(1)
  {
    printf("I am main thread!\n");
    sleep(2);
  }
  return 0;
}

结果:
在这里插入图片描述
4.看是否属于一个进程,分别打印出线程与进程的id号,线程与进程的id号是一致的

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
void *Routine(void *arg)
{
  char *msg = (char*)arg;
  while(1)
  {
    printf("%s:pid:%d,ppid:%d\n",msg,getpid(),getppid());
    sleep(1);
  }
}

int main()
{
pthread_t tid;
  //创建线程
  pthread_create(&tid,NULL,Routine,(void*)"thread 1"); //传thread 1参数

  while(1)
  {
    printf("main thread:pid:%d,ppid:%d\n",getpid(),getppid());
    sleep(2);
  }
  return 0;
}

在这里插入图片描述

5.ps -aL | head -1 && ps -aL | grep mythread(显示两个线程的PID一样)
-L:显示当前的轻量级进程
LWP:轻量级进程ID

OS调度的基本的时候,采用的是LWP,并非是PID!
在这里插入图片描述
Linux中,应用层的线程,与内核的LWP是1:1
6.创建一批线程

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>
void *Routine(void *arg)
{
  char *msg = (char*)arg;
  while(1)
  {
    printf("%s: pid:%d,ppid:%d\n",msg,getpid(),getppid());
    sleep(1);
  }
}

int main()
{
pthread_t tid[5];
  //创建线程
  for(int i = 0; i < 5; i++)
  {
    char buffer[64];
    sprintf(buffer,"thread %d",i);  //把该输出到显示器上的内容输出到字符串中

    pthread_create(&tid[i],NULL,Routine,(void*)buffer); //传thread 1参数
  }



  while(1)
  {
    printf("main thread:pid:%d,ppid:%d\n",getpid(),getppid());
    sleep(2);
  }
  return 0;
}

在这里插入图片描述
7.显示自己线程ID:pthread_self()

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>
void *Routine(void *arg)
{
  char *msg = (char*)arg;
  while(1)
  {
    printf("%s: pid:%d,ppid:%d,tid:%lu\n",msg,getpid(),getppid(),pthread_self());
    sleep(1);
  }
}

int main() 
{
pthread_t tid[5];
  //创建线程
  for(int i = 0; i < 5; i++)
  {
    char buffer[64];
    sprintf(buffer,"thread %d",i);

    pthread_create(&tid[i],NULL,Routine,(void*)buffer); //传thread 1参数
    printf("%s tid is:%lu\n",buffer,tid[i]);
  }
  while(1)
  {
    printf("main thread:pid:%d,ppid:%d,tid:%lu\n",getpid(),getppid(),pthread_self());
    sleep(2);
  }
  return 0;
}

在这里插入图片描述

注意:调用自己线程的ID:pthread _self(),和getpid()类似,但是类型为%lu,此时获得的是用户级原生线程库的线程ID,与LWP的关系是1:1

二、线程的等待

1.线程等待:phread_join(),默认等待以阻塞形式等待,若不等待,则可能会成为僵尸进程,造成内存泄漏
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>
void *Routine(void *arg)
{
  char *msg = (char*)arg;
  int count = 0;
  while(count < 5)
  {
    printf("%s: pid:%d,ppid:%d,tid:%lu\n",msg,getpid(),getppid(),pthread_self());
    sleep(1);
    count++;
  }
  return NULL;
}

int main()
{
pthread_t tid[5];
  //创建线程
  for(int i = 0; i < 5; i++)
  {
    char buffer[64];
    sprintf(buffer,"thread %d",i);

    pthread_create(&tid[i],NULL,Routine,(void*)buffer); //传thread 1参数
    printf("%s tid is:%lu\n",buffer,tid[i]);
  }

    printf("main thread:pid:%d,ppid:%d,tid:%lu\n",getpid(),getppid(),pthread_self());


  //线程等待
  for(int i = 0; i < 5; i++)
  {
    pthread_join(tid[i],NULL);
    printf("thread %d[%lu] ... quit!\n",i,tid[i]);
  }
  return 0;
}

在这里插入图片描述

2.获取退出码

int pthread_join(pthread_t thread, void **retval)
retval:拿到被等待的线程的退出码,通常用来验证代码运行完毕,结果是否正确。

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>
void *Routine(void *arg)
{
  char *msg = (char*)arg;
  int count = 0;
  while(count < 5)
  {
    printf("%s: pid:%d,ppid:%d,tid:%lu\n",msg,getpid(),getppid(),pthread_self());
    sleep(1);
    count++;
  }
  return (void*)10;
}

int main()
{
pthread_t tid[5];
  //创建线程
  for(int i = 0; i < 5; i++)
  {
    char *buffer=(char*)malloc(64);
    sprintf(buffer,"thread %d",i);

    pthread_create(&tid[i],NULL,Routine,(void*)buffer); //传thread 1参数
    printf("%s tid is:%lu\n",buffer,tid[i]);
  }

    printf("main thread:pid:%d,ppid:%d,tid:%lu\n",getpid(),getppid(),pthread_self());


  //线程等待
  for(int i = 0; i < 5; i++)
  {
    void *ret = NULL;
    pthread_join(tid[i],&ret); //获取退出码
    printf("thread %d[%lu] ... quit! code:%d\n",i,tid[i],ret);
  }
  return 0;
}

在这里插入图片描述
另外:多线程需要考虑异常,但是做不到

三、线程的终止

1.为什么等待?

(1)已经退出的线程,其空间没有被释放,仍然在进程的地址空间内
(2)创建新的线程不会复用刚才退出线程的地址空间

2.正常终止的做法

(1).return XXX:在main内return,代表整个进程终止
(2).exit():也是整个进程全部终止
(3).终止某个线程:pthread_exit()
(4).pthread_cancel():取消某个线程,取消成功,退出码为-1
(5).main里面pthread_cancel(tid[0]) 取消其它线程(推荐),取消下标为0的线程

另外:
1.新线程可以取消主线程吗?可以,但是不推荐
2.一般情况下,线程必须被等待,就如同子进程必须被等待一样
3.线程可以不被join,也可以不用,但需要将线程进行分离

四、线程分离

pthread_detach()

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>
void *Routine(void *arg)
{
  pthread_detach(pthread_self()); //分离
  char *msg = (char*)arg;
  int count = 0;
  while(count < 5)
  {
    printf("%s: pid:%d,ppid:%d,tid:%lu\n",msg,getpid(),getppid(),pthread_self());
    sleep(1);
    count++;
  }
  pthread_exit((void*)19); //线程退出码
 // return (void*)10;
}

int main()
{
pthread_t tid[5];
  //创建线程
  for(int i = 0; i < 5; i++)
  {
    char *buffer=(char*)malloc(64);
    sprintf(buffer,"thread %d",i);

    pthread_create(&tid[i],NULL,Routine,(void*)buffer); //传thread 1参数
    printf("%s tid is:%lu\n",buffer,tid[i]);
  }

   while(1){
     printf("main thread:pid:%d,ppid:%d,tid:%lu\n",getpid(),getppid(),pthread_self());
    sleep(1);
   }
/*
  //线程等待
  for(int i = 0; i < 5; i++)
  {
    void *ret = NULL;
    pthread_join(tid[i],&ret); //获取退出码
    printf("thread %d[%lu] ... quit! code:%d\n",i,tid[i],ret);
  }
  */
  return 0;
}

在这里插入图片描述
用户层如何得知对应的线程呢?
线程很多,需要被管理的,Linux不提供真正的线程,只提供LWP,意味着OS只需要对LWP内核执行流进行管理,那供用户使用的接口等其它数据由线程库pthread库来管理
pthread_t类型的线程ID,本质上就是一个进程地址空间上的一个地址。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值