当前位置: 首页 > news >正文

【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 来分离子线程,主线程仍然能够继续执行,进程不会崩溃。

相关文章:

  • 【油漆面积——线段树,扫描线,不用pushdown的特例,pushup兼有cal的性质】
  • 大数据如何帮助你在业务中创造奇迹?
  • 【HarmonyOS Next】图片选择方案
  • 精选Python小项目代码
  • 【前端框架】深入探讨 Vue 3 组件生命周期的变化和最佳实践
  • 卓越设计彰显品质:福特中国“烈马宇宙”项目展示高质量标准
  • linux--关于GCC、动态库静态库
  • kubectl exec 实现的原理
  • 【SQL技术】不同数据库引擎 SQL 优化方案剖析
  • 30天自制操作系统第一天(1)
  • 微信小程序性能优化
  • 寒假第三周周报
  • 基于JAVA的幼儿园管理系统的设计与实现源码(springboot+vue+mysql)
  • [创业之路-307]:如何解读公司的业绩?它与股价变化的关系?
  • c++中std::thread构造函数的注意事项
  • 【Python】Python入门基础——环境搭建
  • 数据库系统原理——第十章数据恢复技术复习题
  • 学习总结三十四
  • Ubuntu20.04部署stable-diffusion-webui环境小记
  • 题海拾贝:英语作文(map)
  • 烤肉店从泔水桶内捞出肉串再烤?西安未央区市监局:停业整顿
  • 伊朗最高领袖顾问:伊朗愿承诺永不制造核武,换取美解除制裁
  • 七旬男子驾“老头乐”酒驾被查,曾有两次酒驾两次肇事记录
  • 加拿大新政府宣誓就职
  • 线下哪些商家支持无理由退货?查询方法公布
  • 技术派|更强的带刀侍卫:从054B型战舰谈谈世界护卫舰发展