CppGuide社区 CppGuide社区
首页
  • 🔥最新谷歌C++风格指南(含C++17/20)
  • 🔥C++17详解
  • 🔥C++20完全指南
  • 🔥C++23快速入门
  • C++语言面试问题集锦
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • 🔥C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 🔥从零用C语言写一个Redis
  • 🔥Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go语言特性

    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 🔥使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
Rust编程指南
  • SQL零基础指南
  • MySQL开发与调试指南
GitHub (opens new window)
首页
  • 🔥最新谷歌C++风格指南(含C++17/20)
  • 🔥C++17详解
  • 🔥C++20完全指南
  • 🔥C++23快速入门
  • C++语言面试问题集锦
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • 🔥C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 🔥从零用C语言写一个Redis
  • 🔥Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go语言特性

    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 🔥使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
Rust编程指南
  • SQL零基础指南
  • MySQL开发与调试指南
GitHub (opens new window)
  • 第1章高频C++11重难点知识解析

  • 第2章Linux GDB高级调试指南

  • 第3章C++多线程编程从入门到进阶

    • 3.1 线程的基本概念
      • 3.2 线程基本操作
      • 3.3 线程函数传C++类实例指针惯用法
      • 3.4 整型变量的原子操作
      • 3.5 Linux线程同步对象
      • 3.6 Windows 线程资源同步对象
      • 3.7 C++ 11/14/17 线程同步对象
      • 3.8 如何确保创建的线程一定运行起来?
      • 3.9 多线程使用锁实践经验总结
      • 3.10 线程局部存储
      • 3.11 C 库的非线程安全函数
      • 3.12 线程池与队列系统的设计
      • 3.13 纤程(Fiber)与协程(Coroutine)
      • 3.14 本章总结
    • 第4章C++网络编程重难点解析

    • 第5章网络通信故障排查常用命令

    • 第6章高性能网络通信协议设计精要

    • 第7章高性能服务结构设计

    • 第8章Redis 网络通信模块源码分析

    • 第9章后端服务重要模块设计探索

    • C++后端开发进阶
    • 第3章C++多线程编程从入门到进阶
    zhangxf
    2023-04-05
    目录

    3.1 线程的基本概念

    线程的英文单词是thread,翻译成对应的中文有”分支“、”枝干“的意思,当然这里翻译成”线程“属于意译了。提到线程就不得不提与线程相关联的另外一个概念”进程“,一个”进程“代表计算机中实际跑起来的一个程序,在现代操作系统的保护模式下,每个进程拥有自己独立的进程地址空间和上下文堆栈。但是就一个程序本身执行的操作来说,进程其实什么也不做(不执行任何进程代码),它只是提供一个大环境容器,在进程中实际的执行体是”线程“。wiki百科上给线程的定义是:

    In computer science, a thread of execution is the smallest sequence of programmed instructions that can be managed independently by a scheduler, which is typically a part of the operating system.

    计算机科学中,线程是操作系统管理的、可以执行编制好的最小单位的指令序列的调度器。

    翻译的有点拗口,通俗地来说,线程是进程中实际执行代码的最小单元,它由操作系统安排调度(何时启动、何时运行和暂停以及何时消亡)。

    进程与线程的区别与关系这里就不再多说了,任何一本关于操作系统的书籍都会有详细的介绍。这里需要重点强调的是如下几个问题,这也是我们在实际开发中使用多线程需要搞明白的问题。

    # 3.1.1 一个进程至少有一个线程

    上文也说了,线程是进程中实际干活的单位,因此一个进程至少得有一个线程,我们把这个线程称之为”主线程“。

    # 3.1.2 主线程退出,支线程也将退出吗?

    在Windows系统中,当一个进程存在多个线程时,如果主线程执行结束了,那么这个时候即使支线程(也可以叫工作线程)还没完成相关的代码执行,支线程也会退出,也就是说,主线程一旦退出整个进程也就结束了。之所以强调这一点是,是因为很多多线程编程的初学者经常在工作线程写了很多逻辑代码,但是没有注意到主线程已经提前退出,导致这些工作线程的代码来不及执行。解决这一问题的方案很多,核心就是让主线程不要退出,或者至少在工作线程完成工作之前主线程不要退出。常见的解决方案有主线程启动一个循环或者主线程等待工作线程退出后再退出(下文将会详细介绍)。

    在Linux系统中,如果主线程退出,工作线程一般不会受到影响,还会继续运行下去,但是此时这个进程就会变成所谓的僵尸进程,这是一种不好的做法,实际开发中应该避免产生僵尸进程。

    # ps -ef 命令查看系统进程列表时,带有<defunct>字样的进程即僵尸进程
    [root@localhost ~]# ps -ef
    UID        PID  PPID  C STIME TTY          TIME CMD
    root         2     0  0 Jan18 ?        00:00:01 [kthreadd]
    root         3     2  0 Jan18 ?        00:00:25 [ksoftirqd/0]
    root         5     2  0 Jan18 ?        00:00:00 [kworker/0:0H]
    root     60928     1  0 14:48 pts/1    00:00:00 [linuxtid] <defunct>
    
    1
    2
    3
    4
    5
    6
    7

    Linux版本众多,在某些Linux版本实现中,主线程退出也会导致支线程退出,这个行为就和Windows上一样了。读者在实际开发时应该以自己的机器测试结果为准。

    # 3.1.3 某个线程崩溃,会导致进程退出吗?

    这是一个常见的面试题,还有一种问法是:进程中某个线程崩溃,是否会对其他线程造成影响?

    一般来说,每个线程都是独立执行的单位,每个线程都有自己的上下文堆栈,一个线程的崩溃不会对其他线程造成影响。但是通常情况下,一个线程崩溃会产生一个进程内的错误,例如在Linux操作系统中,可能会产生一个Segment Fault错误,这个错误会产生一个信号,操作系统默认对这个信号的处理就是结束进程,整个进程都被销毁了,这样的话这个进程中存在的其他线程自然也就不存在了。

    上次更新: 2025/04/01, 20:53:14
    2.12 本章总结与扩展阅读
    3.2 线程基本操作

    ← 2.12 本章总结与扩展阅读 3.2 线程基本操作→

    最近更新
    01
    第二章 关键字static及其不同用法
    03-27
    02
    第一章 auto与类型推导
    03-27
    03
    C++语言面试问题集锦 目录与说明
    03-27
    更多文章>
    Copyright © 2024-2025 沪ICP备2023015129号 张小方 版权所有
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式