Linux中主线程和子线程的终止次序

2023-11-09

Linux中pthread是我们进行多线程并发时经常使用的,pthread创建的子线程和主线程的终止顺序有什么样的关系,下面通过代码来总结下。

在代码测试前,先说下结论:

      (1)主线程和子线程之间没有必然的退出次序关系。主线程退出,子线程可以继续执行;子线程退出,主线程也可以继续执行。

      (2)程序加载到内存中执行的时候,进程就会生成一个主线程。虽然主线程和子线程之间没有必然的退出次序关系,但是如果进程终止,那么进程下所有的线程都会终止。

1. 子线程先终止,主线程后终止。 

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

void printids(const char *str) {
    pid_t pid = getpid();
    pthread_t tid = pthread_self();
    printf("%s pid: %u, tid: %u, tid in 0x presentation: 0x%x.\n",str, (unsigned int)pid, (unsigned int)tid, (unsigned int)tid);
}

void *func(void *arg) {
    printids("descendant thread");
    pthread_detach(pthread_self());
    return ((void*)0);
}

int main(void) {
    pthread_t myid;
    pthread_create(&myid, NULL, func, NULL);
    
    sleep(1);  // 等待子线程先退出
    printids("main thread");

    return 0;
}

运行结果: 

2. 进程结束,所有线程都终止。 

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

void printids(const char *str) {
    pid_t pid = getpid();
    pthread_t tid = pthread_self();
    printf("%s pid: %u, tid: %u, tid in 0x presentation: 0x%x.\n",str, (unsigned int)pid, (unsigned int)tid, (unsigned int)tid);
}

void *func(void *arg) {
    sleep(1);  // 等待主线程先退出
    printids("descendant thread");
    pthread_detach(pthread_self());
    return ((void*)0);
}

int main(void) {
    pthread_t myid;
    pthread_create(&myid, NULL, func, NULL);
    
    // sleep(1);  // 等待子线程先退出
    printids("main thread");

    return 0;  //进程退出,系统清除所有资源
}

运行结果: 
 
此时,由于进程退出,该进程中的所有线程都会终止,系统回收所有的资源,因此子线程还没来得及输出pid和tid就已经退出了。

3、主线程先终止,子线程后终止。

主线程需要调用 pthread_exit() 终止,注意和示例2的区别。

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

void printids(const char *str) {
    pid_t pid = getpid();
    pthread_t tid = pthread_self();
    printf("%s pid: %u, tid: %u, tid in 0x presentation: 0x%x.\n",str, (unsigned int)pid, (unsigned int)tid, (unsigned int)tid);
}

void *func(void *arg) {
    sleep(1);  // 等待主线程先退出
    printids("descendant thread");
    pthread_detach(pthread_self());
    return ((void*)0);
}

int main(void) {
    pthread_t myid;
    pthread_create(&myid, NULL, func, NULL);
    
    printids("main thread");
    pthread_exit(NULL);

    return 0;  //进程退出,系统清除所有资源
}

运行结果:

When you program with POSIX Threads API,there is one thing about pthread_exit() that you may ignore for 
mistake. Insubroutines that complete normally, there is nothing special you have to dounless you want 
to pass a return code back using pthread_exit(). The completionwon’t affect the other threads which 
were created by the main thread of thissubroutine. However, in main(), when the code has been executed 
to the end,there could leave a choice for you. If you want to kill all the threads that main() created 
before, you can dispense with calling any functions. But if you want to keep the process and all the 
other threadsexcept for the main thread alive after the exit of main(), then you can call pthread_exit() 
to realize it. And any files opened inside the main thread will remain openafter its termination.

主进程退出后,子进程并没有退出,而是继续执行。

 

POSIX标准定义: 

按照POSIX标准定义,当主线程在子线程终止之前调用pthread_exit()时,子线程是不会退出的。

注意:这里在main函数中调用pthread_exit()只会是主线程退出,而进程并未退出。参照CSAPP中的讲解,当主线程执行pthread_exit()之后,主线程终止,进程并未终止,而是等待所有的子线程终止之后再结束。

总结: 

一个线程的终止不会影响到另外一个线程。但是进程结束,该进程下所有线程也会立马终止,所有资源会被回收。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux中主线程和子线程的终止次序 的相关文章

随机推荐

  • Go Web编程实战(2)----流程控制语句

    目录 流程控制语句 if else语句 for循环语句 用for循环实现do while 用for循环实现while break指定跳出循环 continue语句 for range循环 遍历数组 遍历字符串 遍历map 遍历通道 chan
  • c语言程序位置式pid算法,增量式与位置式PID算法(C语言实现与电机控制项目)...

    4 2核心代码 函数功能 增量PI控制器 入口参数 编码器测量值 目标速度 返回 值 电机PWM 根据增量式离散PID公式 pwm Kp e k e k 1 Ki e k Kd e k 2e k 1 e k 2 e k 代表本次偏差 e k
  • linux 终端使用aplay播放wav

    aplay D plughw 0 0 xxx wav plughw后面的0 0指的是card0 device0 声卡id和设备id 根据个人情况会有不同 声卡id和设备id可以通过aplay l命令来查看 比如 upsquared ubun
  • Redis5.0集群搭建(Redis Cluster)

    Redis集群 redis集群是一个由多个主从节点群组成的分布式服务器群 它具有复制 高可用和分片特性 Redis集群不需要sentinel也能完成节点移除和故障转移的功能 需要将每个节点设置成集群模式 这种集群模式没有中心节点 可水平扩展
  • [1116]mobaxterm使用rz/sz

    安装 yum y install lrzsz 下载 步骤1 sz filename 步骤2 ctrl 鼠标右键 步骤3 Receive file using Z modem 上传 步骤1 rz 步骤2 ctrl 鼠标右键 步骤3 Send
  • ArchLinux安装fcitx5以及拼音输入法

    简介 输入法引擎 需要注意的是 fcitx5 只是提供了基本框架 基本框架只对英文提供了输入支持 如果需要输入其他语言 则需要安装相应的输入法引擎 中文 fcitx5 chinese addons 包含了大量中文输入方式 拼音 双拼 五笔拼
  • SMTP邮件格式、SMTP 协议,SMTP的MIME写法,SMTP发送HTML邮件

    转载 http blog sina com cn s blog 759444350100vx8u html MIME邮件格式 在RFC 2822文档中定义了简单的ASCII编码的Email的邮件格式 然而随着Internet的发展 Emai
  • JSP JSTL 判断List 大小

    JSTL判断List 大小必须先引入的二个核心包 jsp页面判断获得action设置attribute的List是否为空或者list size的长度 就可以用fn这个标签
  • python写的一个-批量下载股票年报的小工具

    python写的一个 批量下载股票年报的小工具 from urllib import request import requests import os import openpyxl print os getcwd def getKeyL
  • Java中怎么定义字符串?

    字符串是 Java 中特殊的类 使用方法像一般的基本数据类型 被广泛应用在 Java 编程中 Java 没有内置的字符串类型 而是在标准 Java 类库中提供了一个 String 类来创建和操作字符串 在 Java 中定义一个字符串最简单的
  • oracle 学习之:for循环中包涵select语句

    oracle中的for循环用法比较简单 但是在一次用到包涵select语句的for循环时 还是发现了一些自己以前没有注意的东西 我的代码如下 declare val1 date val2 date begin for i in select
  • pc端微信二维码支付流程及问题排查

    场景 在做pc端的支付时 我们常用的就是生成二维码让用户去扫码支付 like this 当然你想像我一样有个二维码支付的图片 还需要先申请微信支付的native支付功能 native支付会提供一个二维码供用户扫码 页面内 通常会有一个按钮
  • Rust学习记录 -> 关于Crates.io的问题

    文章目录 前言 问题描述与解析 1 版本更迭带来的依赖包适配问题 2 openssl 总结 前言 最近我在使用rust语言编写一个商场后端demo时 由于需要与mysql进行交互以及序列化等操作 所以通过crates io下载了许多外部依赖
  • SLAM评估工具evo的使用

    evo官方指南 参考博客 lt 官方手册 这篇参考博客 完全可以掌握evo的基本操作 gt Then 实践出真知 1 安装evo sudo apt install python pip pip install evo upgrade no
  • 阿里云图标使用 (symbol 引用方式)

    阿里云图标网址 https www iconfont cn 一 登录注册 这个简单 就不说了 二 给当前项目找图库 2 1 添加项目 2 2 寻找图标添加入库 添加入库 2 3 打开入库 的图标添加到指定项目 添加到当前项目 1 2 三 项
  • 在线考试平台搭建

    出于工作需要 在万能的Github上找到的考试平台 在此感谢平台的创作者 github https github com YXJ2018 SpringBoot Vue OnlineExam 在线考试系统 下载该项目后 因为各种各样的原因 导
  • 【Vue3】Fragment组件、Teleport组件和Suspense组件

    Fragment组件 在Vue2中 组件必须有一个根标签 在Vue3中 组件可以没有根标签 内部会将多个标签包含在一个Fragment虚拟元素中 好处 减少标签层次 减少内侧占用 Teleport组件 是一种能够将我们的组件html结构移动
  • 【GIT 坑&常见问题】

    文章目录 前言 git github 使用问题 坑 连接不上github 1 过后再连 2 使用某些途径 3 修改git 的http 和https的代理 4 使用VS 在创建远程仓库的时候 别在远程仓库进行修改 git LFS上传超过100
  • C++ try{} catch(…){} 与 Throw()的编译器优化

    try catch 用 try catch 来捕获C 中一些意想不到的异常 这种方法在VC中其实是靠不住的 例如下面的代码 try BYTE pch pch BYTE 00001234 给予一个非法地址 pch 6 对非法地址赋值 会造成A
  • Linux中主线程和子线程的终止次序

    Linux中pthread是我们进行多线程并发时经常使用的 pthread创建的子线程和主线程的终止顺序有什么样的关系 下面通过代码来总结下 在代码测试前 先说下结论 1 主线程和子线程之间没有必然的退出次序关系 主线程退出 子线程可以继续