【c++】【Linux】【进程】线程终止/崩溃 会导致进程终止/崩溃 吗?

【c++】【Linux】【进程】线程终止/崩溃 会导致进程终止/崩溃 吗?

1.线程终止会导致进程终止吗?

在操作系统中,线程是进程的基本执行单元,一个进程可以包含一个或多个线程。

  • 当一个子线程终止时,进程并不会因此自动终止,其他线程(包括主线程)仍然会继续运行。
  • 主线程都终止时,进程才会结束。

1子线程先结束,主线程继续执行,进程不会终止

1.1使用detach(): 将子线程与主线程分离
#include <iostream>
#include <thread>
#include <chrono>

void worker() {
    std::cout << "子线程开始执行。" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));  // 模拟一些工作
    std::cout << "子线程结束。" << std::endl;
}

int main() {
    std::cout << "主线程开始执行。" << std::endl;

    std::thread t(worker);  // 创建子线程
    t.detach();  // 将子线程与主线程分离,主线程不等待子线程

    std::cout << "主线程继续执行,不等待子线程。" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(5));  // 主线程继续执行
    std::cout << "主线程结束。" << std::endl;

    return 0;
}
  1. List itemstd::thread t(worker): 这行代码创建了一个新的子线程,执行 worker 函数。
  2. t.detach(): 将子线程与主线程分离,使得主线程不会等待子线程完成。子线程将独立执行。
  3. std::this_thread::sleep_for(std::chrono::seconds(5)): 主线程继续执行,并且睡眠 5 秒,确保子线程有时间执行。
  4. 子线程在 2 秒后结束,主线程在 5 秒后结束。
    运行结果:
    在这里插入图片描述
  • 主线程和子线程各自独立运行,互不干扰。
  • 即使子线程先于主线程结束,主线程仍会继续执行,直到完成其自身的任务。
1.2不使用detach(): 将子线程与主线程分离
#include <iostream>
#include <thread>
#include <chrono>

void worker() {
    std::cout << "子线程开始执行。" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));  // 模拟一些工作
    std::cout << "子线程结束。" << std::endl;
}

int main() {
    std::cout << "主线程开始执行。" << std::endl;

    std::thread t(worker);  // 创建子线程

    std::cout << "主线程继续执行,不等待子线程。" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(5));  // 主线程继续执行
    std::cout << "主线程结束。" << std::endl;

    return 0;
}

运行结果:
程序抛出了一个异常,但是异常没有被正确处理,但是主线程继续执行
在这里插入图片描述

1.3 使用 join(): 主线程等待子线程结束
#include <iostream>
#include <thread>
#include <chrono>

void worker() {
    std::cout << "子线程开始执行。" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(5));
    std::cout << "子线程结束。" << std::endl;
}

int main() {
    std::cout << "主线程开始执行。" << std::endl;

    std::thread t(worker);  // 创建子线程

    // 使用 join() 确保主线程等待子线程完成
    t.join();

    std::cout << "主线程结束。" << std::endl;

    return 0;
}

运行结果:
主线程等待子线程结束,整个进程再结束
在这里插入图片描述

2主线程先结束,其他线程被迫终止,进程也终止

#include <iostream>
#include <thread>
#include <chrono>

void worker() {
    std::cout << "子线程开始执行。" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(10));  // 模拟一些工作
    std::cout << "子线程结束。" << std::endl;
}

int main() {
    std::cout << "主线程开始执行。" << std::endl;

    std::thread t(worker);  // 创建子线程

    std::this_thread::sleep_for(std::chrono::seconds(2));  // 主线程继续执行
    std::cout << "主线程结束。" << std::endl;

    return 0;
}


在这里插入图片描述

  • 主线程先于子线程结束,子线程被迫中止,进程也结束了

2.线程崩溃会导致进程崩溃吗?

  • 子线程崩溃不一定会导致进程崩溃,关键在于如何处理子线程中的错误和异常。

2.1子线程崩溃导致进程崩溃的情况

2.1.1子线程访问非法内存(进程崩溃)

(1)

#include <iostream>
#include <pthread.h>

void* thread_func(void* arg) {
    // 模拟非法内存访问
    int* ptr = nullptr;
    *ptr = 42;  // 触发崩溃
    return nullptr;
}

int main() {
    pthread_t thread;

    // 创建子线程
    if (pthread_create(&thread, nullptr, thread_func, nullptr) != 0) {
        std::cerr << "Failed to create thread." << std::endl;
        return 1;
    }

    pthread_join(thread, nullptr);  // 等待子线程结束

    std::cout << "Main thread continues running." << std::endl;

    return 0;
}

执行结果
在这里插入图片描述
子线程访问了一个空指针,导致了段错误(Segmentation fault),进程崩溃。
(2)

#include <iostream>
#include <thread>
#include <string>

void thread_func(char* str) {
    // 尝试修改只读字符串
    str[0] = 'X';  // 修改字符串的第一个字符
    std::cout << "Thread modified string: " << str << std::endl;
}

int main() {
     char * str = "Hello, World!";  // 常量字符串(只读数据)

    // 创建多个线程来修改该字符串
    std::thread t1(thread_func, std::ref(str));
    std::thread t2(thread_func, std::ref(str));

    t1.join();
    t2.join();

    return 0;
}

执行结果
在这里插入图片描述
子线程访问了无法被修改的常量区数据,导致了段错误(Segmentation fault),进程崩溃。

2.1.2 子线程抛出未捕获的异常(进程崩溃)

如果子线程抛出未捕获的异常,默认情况下会导致调用 std::terminate,从而导致进程崩溃。

#include <iostream>
#include <pthread.h>
#include <stdexcept>

void* thread_func(void* arg) {
    // 模拟子线程中的异常
    throw std::runtime_error("Child thread crashed!");
    return nullptr;
}

int main() {
    pthread_t thread;

    // 创建子线程
    if (pthread_create(&thread, nullptr, thread_func, nullptr) != 0) {
        std::cerr << "Failed to create thread." << std::endl;
        return 1;
    }

    pthread_join(thread, nullptr);  // 等待子线程结束

    std::cout << "Main thread continues running." << std::endl;

    return 0;
}

执行结果
在这里插入图片描述

  • 子线程崩溃而没有适当的处理,std::terminate 会导致进程崩溃
  • 子线程未捕获异常而触发了 std::terminate,导致整个进程崩溃,而不仅仅是子线程。
    这是因为,在多线程程序中,std::terminate 的行为会影响整个进程,即使子线程崩溃,主线程仍然会被中断并导致进程崩溃。

2.2子线程崩溃,但进程继续运行(捕获异常或通过错误处理)

2.2.1子线程异常被捕获,进程不崩溃
#include <iostream>
#include <pthread.h>
#include <stdexcept>

void* thread_func(void* arg) {
    try {
        // 模拟子线程中的异常
        throw std::runtime_error("Child thread crashed!");
    } catch (const std::exception& e) {
        std::cerr << "Caught exception in child thread: " << e.what() << std::endl;
    }
    return nullptr;
}

int main() {
    pthread_t thread;

    // 创建子线程
    if (pthread_create(&thread, nullptr, thread_func, nullptr) != 0) {
        std::cerr << "Failed to create thread." << std::endl;
        return 1;
    }

    pthread_join(thread, nullptr);  // 等待子线程结束

    std::cout << "Main thread continues running." << std::endl;

    return 0;
}

执行结果
在这里插入图片描述

2.2.2 子线程崩溃(但是通过分离线程,主线程继续执行)
#include <iostream>
#include <pthread.h>
#include <stdexcept>

void* thread_func(void* arg) {
    throw std::runtime_error("Child thread crashed!");
    return nullptr;
}

int main() {
    pthread_t thread;

    // 创建子线程
    if (pthread_create(&thread, nullptr, thread_func, nullptr) != 0) {
        std::cerr << "Failed to create thread." << std::endl;
        return 1;
    }

    pthread_detach(thread);  // 分离子线程,主线程继续执行

    std::cout << "Main thread continues running." << std::endl;

    return 0;
}

执行结果
在这里插入图片描述
子线程抛出异常,但因为子线程已经分离,主线程不会被阻塞,进程继续运行,主线程完成执行。

总结

子线程崩溃导致进程崩溃的情况: 如果子线程因为非法内存访问(如空指针解引用)或者未捕获的异常(导致 std::terminate),则进程会崩溃。
子线程崩溃但不导致进程崩溃: 如果子线程抛出异常且异常被捕获,或者使用了 pthread_detach 来分离子线程,主线程仍然能够继续执行,进程不会崩溃。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/970818.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【动手学运动规划】5.5 基于PiecewiseJerk的路径优化方法

知我者&#xff0c;谓我心忧. 不知我者&#xff0c;谓我何求。— 佚名 黍离 &#x1f3f0;代码及环境配置&#xff1a;请参考 环境配置和代码运行! PiecewiseJerkOptimizer是Apollo中planning模块生成Path/Speed曲线的优化方法. 基于Frenet坐标系, 生成平滑, 安全的目标曲线. …

图论入门算法:拓扑排序(C++)

上文中我们了解了图的遍历(DFS/BFS), 本节我们来学习拓扑排序. 在图论中, 拓扑排序(Topological Sorting)是对一个有向无环图(Directed Acyclic Graph, DAG)的所有顶点进行排序的一种算法, 使得如果存在一条从顶点 u 到顶点 v 的有向边 (u, v) , 那么在排序后的序列中, u 一定…

英国学术论文规范,学术来源的基本知识

学术来源&#xff08;scholarly source&#xff09;&#xff0c;指的是在某一特定的学术研究领域由专家所写&#xff0c;给同行或者对此专业领域有兴趣的人所阅读&#xff0c;提供相关分析素材的研究成果。在国外留学中&#xff0c;虽然平时学校要求完成的作业多为reports&…

Java运维实战:问题定位-CPU突增排查

java程序最常见的故障场景就是CPU徒增的情况了&#xff0c;本片文章为你讲解java程序CPU突增的情况怎么进行排查 1、获取CPU消耗高的线程ID top -Hp 进程ID 然后输入大写P&#xff08;shiftp&#xff09;&#xff0c;就会将这个进程下的线程按照CPU消耗进行排序展示。 举例 然…

使用 Ansys MotorCAD 进行轴向磁通电机设计

新的 MotorCAD 机器拓扑&#xff1a;轴向磁通电机 轴向磁通量可用拓扑 Ansys MotorCAD支持3种不同的轴向磁通拓扑&#xff0c;包括&#xff08;双转子 - 单定子&#xff09;、&#xff08;单转子 - 单定子&#xff09;和&#xff08;单转子 - 双定子&#xff09; 双转子 - 单…

【深度学习】深度学习和强化学习算法——深度 Q 网络DQN

深度 Q 网络&#xff08;Deep Q-Network, DQN&#xff09; 详解 什么是DQNDQN 的背景DQN 训练流程 2 DQN 的核心思想2.1 经验回放&#xff08;Experience Replay&#xff09;2.2 目标网络&#xff08;Target Network&#xff09;2.3 ε-贪心策略&#xff08;ε-Greedy Policy&a…

学习数据结构(10)栈和队列下+二叉树(堆)上

1.关于栈和队列的算法题 &#xff08;1&#xff09;用队列实现栈 解法一&#xff1a;&#xff08;参考代码&#xff09; 题目要求实现六个函数&#xff0c;分别是栈初始化&#xff0c;入栈&#xff0c;移除并返回栈顶元素&#xff0c;返回栈顶元素&#xff0c;判空&#xff0…

芯片引脚描述或电路原理图中的Ipd、Ipu是什么意思?

问&#xff1a;物理层芯片KSZ8081RNB的Data Sheet对某些引脚类型的说明如下&#xff1a; 请说明其中Ipd、Ipu的意思是什么&#xff1f; 答&#xff1a; I&#xff1a;表示该引脚是一个 输入引脚&#xff0c;即该引脚用于接收信号。O&#xff1a;表示该引脚是一个 输出引脚&a…

[操作系统] 基础IO:系统文件I/O

在 Linux 操作系统中&#xff0c;文件 I/O&#xff08;输入/输出&#xff09;是程序与文件系统交互的基础。理解文件 I/O 的工作原理对于编写高效、可靠的程序至关重要。本文将深入探讨系统文件 I/O 的机制。 一种传递标志位的方法 在 Linux 中&#xff0c;文件的打开操作通常…

Mybatis-扩展功能

逻辑删除乐观锁 MyBatisPlus从入门到精通-3&#xff08;含mp代码生成器&#xff09; Db静态工具类 Spring依赖循环问题 代码生成器 MybatisPlus代码生成器 枚举处理器 我们这里用int来存储状态 需要注解&#xff0c;很不灵活 希望用枚举类来代替这个Integer 这样的话我…

ECharts 实战指南:组件封装+地图轮廓高亮 + 自定义 Tooltip+轮播+锥形柱子

大家好&#xff0c;我是一诺。今天我们将深入探讨 ECharts&#xff0c;这个功能强大的数据可视化库。 无论你是已经在使用 ECharts&#xff0c;还是正计划用它来创建一些炫酷的图表&#xff0c;这篇文章都会对你有所帮助。 我们将从渲染模式开始&#xff0c;逐步深入到如何封…

【MyBatis】_使用XML实现MyBatis

目录 1. 配置yml配置文件 1.2 配置数据库 1.3 配置xml的路径 2. xml文件中实现数据库的增删查改操作 2.1 各文件内容 2.2 编写细节 MyBatis作为一个持久层框架&#xff0c;用于进行数据库操作。 MyBatis的实现方式有两种&#xff1a;&#xff08;1&#xff09;注解&…

单链表的概念,结构和优缺点

1. 概念 链表是一种物理存储结构上非连续&#xff0c;非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 2. 单链表的结构 单链表是由一系列节点组成的线性结构&#xff0c;每个结点包含两个域。&#xff1a;数据域和指针域。 数据域用来…

PerfMonitor高效处理器性能监控与分析利器

在追求极致电脑性能的道路上&#xff0c;一款精准、高效的处理器性能监控工具无疑是每位DIY爱好者和系统管理员的必备之选。今天&#xff0c;我们为大家带来的是CPUID出品的PerfMonitor 2&#xff0c;这款绿色小巧的软件以其强大的功能和直观的界面设计&#xff0c;赢得了广大用…

【C++】基础入门(详解)

&#x1f31f; Hello&#xff0c;我是egoist2023&#xff01; &#x1f30d; 种一棵树最好是十年前&#xff0c;其次是现在&#xff01; 目录 输入&输出 缺省参数(默认参数) 函数重载 引用 概念及定义 特性及使用 const引用 与指针的关系 内联inline和nullptr in…

数据恢复-02-故障硬盘的检测

任务描述 客户报修一故障硬盘&#xff0c;据客户描述&#xff0c;由于自己所用的台式机硬盘容量过小因而想更换一块大容量硬盘。但是在拆卸的过程中不慎将硬盘滑落在地&#xff0c;尝试对电脑进行开机&#xff0c;发现无法正常进入操作系统&#xff0c;故判断可能是硬盘故障导…

04性能监控与调优篇(D5_JVM优化)

目录 一、我们为什么要对jvm做优化&#xff1f; 二、jvm的运行参数 1. 三种参数类型 1.1. 标准 1> 参数介绍 2> 实战 3> -server与-client参数 1.2. -X参数 1> 参数介绍 2> -Xint、-Xcomp、-Xmixed 1.3. -XX参数 -Xms与-Xmx参数 2. 查看jvm的运行参…

IntelliJ IDEA 接入 AI 编程助手(Copilot、DeepSeek、GPT-4o Mini)

IntelliJ IDEA 接入 AI 编程助手&#xff08;Copilot、DeepSeek、GPT-4o Mini&#xff09; &#x1f4ca; 引言 近年来&#xff0c;AI 编程助手已成为开发者的高效工具&#xff0c;它们可以加速代码编写、优化代码结构&#xff0c;并提供智能提示。本文介绍如何在 IntelliJ I…

嵌入式软件、系统、RTOS(高软23)

系列文章目录 4.2嵌入式软件、系统、RTOS 文章目录 系列文章目录前言一、嵌入式软件二、嵌入式系统三、嵌入式系统分类四、真题总结 前言 本节讲明嵌入式相关知识&#xff0c;包括软件、系统。 一、嵌入式软件 二、嵌入式系统 三、嵌入式系统分类 四、真题 总结 就是高软笔记…

spring 学习 (注解)

目录 前言 常用的注解 须知 1 Conponent注解 demo&#xff08;案例&#xff09; 2 ControllerServiceRepository demo(案例&#xff09; 3 ScopeLazyPostConstructPreDestroy demo(案例&#xff09; 4 ValueAutowiredQualifierResource demo(案例&#xff09; 5 Co…