【C/C++】线程状态以及转换
文章目录
- 线程状态以及转换
- 1 基本状态
- 1.1 新建(New)
- 1.2 就绪(Ready / Runnable)
- 1.3 运行中(Running)
- 1.4 阻塞/等待(Blocked / Waiting / Sleeping)
- 1.5 挂起(Suspended)
- 1.6 终止(Terminated / Dead / Exit)
- 注意点
- 2 状态转换
- 2.1 C/C++ 线程状态转换图(基于 Linux/POSIX 和 `std::thread`)
- 2.2 状态转换说明
- 2.3 示例:多个状态的转换代码
- 3 调试
- 3.1 Linux 中线程/进程的典型状态码
- 3.2 深入 `/proc/[pid]/task/` 查看线程状态
- 3.3 状态之间的实际转换(C++ 映射)
- 3.5 调试技巧
- 总结:线程状态的决定者是谁?
线程状态以及转换
线程的基本状态通常用于描述线程在程序执行过程中的生命周期。
1 基本状态
1.1 新建(New)
- 说明:线程对象已经创建,但尚未启动。
- 示例(C++):
std::thread t(myFunction);
(如果尚未调用join()
或detach()
)
1.2 就绪(Ready / Runnable)
- 说明:线程已经准备好运行,但由于 CPU 正忙,暂时未被调度执行。
- 特征:已具备运行条件,等待调度。
1.3 运行中(Running)
- 说明:线程正在由 CPU 调度并执行任务。
- 特征:只有一个线程能在某一时刻占用一个 CPU 核心运行。
1.4 阻塞/等待(Blocked / Waiting / Sleeping)
-
说明:线程暂时无法继续运行,处于等待某些资源或事件状态。
-
常见原因:
- 等待锁(mutex)释放
- 等待条件变量(
std::condition_variable
) - 调用了
sleep_for()
/sleep_until()
- 等待 I/O 操作完成
1.5 挂起(Suspended)
- 说明:线程被人为暂停,暂时不会被调度(某些系统中才存在,如 Windows)。
- 补充:这不是所有系统都显式支持的状态。
1.6 终止(Terminated / Dead / Exit)
-
说明:线程执行完任务或被强制终止,生命周期结束。
-
注意事项:
- 线程终止后不能被重启。
- C++ 中,必须在适当时机调用
join()
或detach()
,否则可能引发资源泄露。
注意点
std::thread
构造后即启动,不能“延迟启动”。join()
:主线程等待子线程执行完毕。detach()
:子线程后台运行,主线程不再关心其状态。- 未调用
join()
或detach()
就析构std::thread
,会导致程序崩溃。
2 状态转换
在 C/C++ 中,线程状态的转换并不像 Java 那样有统一的虚拟机控制模型,而是依赖于底层操作系统(如 Linux、Windows)调度机制。C++ 本身通过 std::thread
提供了对系统线程(如 POSIX Threads 或 Windows Threads)的封装,但不显式暴露线程状态。
结合操作系统线程模型,理解 C/C++ 中线程状态的转换路径。
2.1 C/C++ 线程状态转换图(基于 Linux/POSIX 和 std::thread
)
简单版本
[New] ↓[Ready] ↔ [Running] → [Terminated]↑ ↓[Blocked] ←---
+--------+ thread constructor| New | --------------------------++--------+ || v| +-------------+| OS调度 | Runnable |+----------------------> +-------------+| |v |+--------------+ | 被抢占或 yield| Running | <----++--------------+|+----------------------+------------------------------+| | |v v v
[Waiting on lock] [Waiting on cond_var] [sleep_for / sleep_until]Blocked Waiting (CondVar) Sleeping+ + +| | |+---------> 信号/条件满足/定时器超时 <---------------+|v+--------------+| Runnable |+--------------+|v+--------------+| Running |+--------------+|执行结束 or 异常|v+--------------+| Terminated |+--------------+
Linux 实际版
+-------------+| Running | <--------++-------------+ || ^ |preempt schedule |v | |+-------------+ || Runnable | ---------++-------------+|+------+------+| |+-------+ +--------+| Sleep | | Disk || (S) | | Sleep |+-------+ | (D) || +--------+| |v v+---------------------+| Runnable |+---------------------+(via wakeup or I/O completion)
2.2 状态转换说明
状态名称 | 触发条件 | 示例代码 |
---|---|---|
New → Runnable | 创建线程对象 std::thread t(...) | std::thread t(myFunc); |
Runnable → Running | 被操作系统调度 | 自动完成,无需显式操作 |
Running → Blocked | 获取互斥锁失败(如 mutex.lock() ) | std::unique_lock<std::mutex> lock(m); |
Running → Waiting | 调用 condition_variable.wait() | cv.wait(lock); |
Running → Sleeping | 调用 std::this_thread::sleep_for(...) | std::this_thread::sleep_for(1s); |
Blocked/Waiting/Sleeping → Runnable | 条件满足/超时/锁释放 | 由 OS 处理,代码中不可见 |
Running → Terminated | 线程函数返回/异常 | 函数结束或 return |
2.3 示例:多个状态的转换代码
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>std::mutex mtx;
std::condition_variable cv;
bool ready = false;void worker() {std::unique_lock<std::mutex> lock(mtx);std::cout << "Worker: waiting...\n";// Running → Waiting(挂起等待条件变量)cv.wait(lock, [] { return ready; });std::cout << "Worker: resumed and working...\n";// Running → Sleepingstd::this_thread::sleep_for(std::chrono::seconds(1));std::cout << "Worker: finished.\n";// → Terminated
}int main() {std::thread t(worker);std::this_thread::sleep_for(std::chrono::seconds(2));{std::lock_guard<std::mutex> lock(mtx);ready = true;std::cout << "Main: notifying worker...\n";}cv.notify_one();t.join();
}
执行结果
Worker: waiting...
Main: notifying worker...
Worker: resumed and working...
Worker: finished.
3 调试
3.1 Linux 中线程/进程的典型状态码
运行命令如:
ps -o pid,tid,stat,comm -L -p <pid>
或者使用 top
,会看到类似以下状态码:
例如输出:
PID TID STAT COMMAND
12345 12345 Ss my_program
12345 12346 Sl my_program
12345 12347 Rl my_program
12345 12348 S my_program
Ss
:主线程,sleeping 且为 session leader。Sl
:sleeping + 多线程(L)。Rl
:runnable + 多线程(L)。S
:普通 sleeping 线程。
状态码 | 含义 | 说明 |
---|---|---|
R | Running / Runnable | 正在运行,或在运行队列中等待调度 |
S | Sleeping (Interruptible) | 可中断的睡眠,等待事件或条件,如 sleep() 、read() |
D | Uninterruptible sleep | 不可中断的睡眠(通常为 IO),如等待磁盘或网络 |
T | Traced / Stopped | 被调试器暂停或收到 SIGSTOP 信号 |
Z | Zombie | 僵尸进程,子进程已终止但父进程未调用 wait() |
X | Dead | 非正常终止(很少见) |
3.2 深入 /proc/[pid]/task/
查看线程状态
Linux 把每个线程当作一个任务(task),在 /proc/[pid]/task/
下有所有线程的子目录:
ls /proc/<pid>/task/
然后可以查看每个线程状态:
cat /proc/<pid>/task/<tid>/status
输出中有一行:
State: S (sleeping)
其他可能值包括:
R (running)
D (disk sleep)
T (stopped)
Z (zombie)
3.3 状态之间的实际转换(C++ 映射)
Linux 状态 | 对应 C++ 场景 |
---|---|
R (Runnable) | 正在执行或准备被调度,CPU 调度队列中 |
S (Sleeping) | std::this_thread::sleep_for 、等待条件变量、I/O 等 |
D (Disk Sleep) | 被阻塞在磁盘或网络 I/O(不可中断) |
T (Stopped) | 被调试或 SIGSTOP 暂停 |
Z (Zombie) | 线程/进程退出但未被 join() /wait() |
3.5 调试技巧
htop
可视化线程状态
htop
# F2 -> Display options -> Show custom thread names (如你设置了)
gdb
附加调试线程状态
gdb -p <pid>
info threads
perf top
查看哪些线程/函数在消耗 CPU
总结:线程状态的决定者是谁?
决定因素 | 状态 |
---|---|
程序员代码 | 睡眠、等待、join 等显式操作 |
操作系统调度器 | Running / Runnable 切换、抢占等 |
锁竞争 | Blocked(mutex、spinlock) |
相关文章:
【C/C++】线程状态以及转换
文章目录 线程状态以及转换1 基本状态1.1 新建(New)1.2 就绪(Ready / Runnable)1.3 运行中(Running)1.4 阻塞/等待(Blocked / Waiting / Sleeping)1.5 挂起(Suspended&am…...
从零开始:Python语言进阶之异常处理
一、认识异常:程序运行中的“意外事件” 在编写Python程序时,即使代码语法完全正确,运行过程中也可能遭遇各种意外情况。这些意外被称为异常,它们会打断程序的正常执行流程。例如,当我们尝试打开一个不存在的文件、用0…...
关于vue彻底删除node_modules文件夹
Vue彻底删除node_modules的命令 vue的node_modules文件夹非常大,常规手段根本无法删除. 解决方法: 在node_modules文件夹所在的路径运行命令窗口,并执行下面的命令. npm install rimraf -g rimraf node_modules说明: npm install rimraf -g 该命令是安装 node…...

如何制作可以本地联网搜索的MCP,并让本地Qwen3大模型调用搜索回答用户问题?
环境: SearXNG Qwen3-32B-FP8 vllm 0.8.5 问题描述: 如何制作可以本地联网搜索的MCP,并让本地Qwen3大模型调用搜索回答用户问题? 解决方案: 一、安装searxng 1.按需新建模型相关文件夹 mkdir MCP chmod 777 /mnt/program/MCP2.配置conda源 nano ~/.condarc nano…...

服务器硬盘虚拟卷的处理
目前的情况是需要删除逻辑卷,然后再重新来弄一遍。 数据已经备份好了,所以不用担心数据会丢失。 查看服务器的具体情况 使用 vgdisplay 操作查看服务器的卷组情况: --- Volume group ---VG Name vg01System IDFormat …...

一个国债交易策略思路
该国债交易策略的核心在于通过分析历史价格数据来识别市场趋势,并在趋势确认时进行开仓操作。策略的设计思路结合了价格波动范围的计算和市场波动性的评估,旨在捕捉市场的短期趋势并控制风险。 首先,策略通过对过去5根K线的最高价和最低价进行…...
Linux常用下载资源命令
wget命令 基本用法 wget -O http://example.com/file.zip-O 参数表示将文件保存为原始文件名。 如果需要指定文件名,可以使用 -o 参数: wget -o custom_name.zip http://example.com/file.zip-P :指定下载文件的保存路径。 wget -P /path/…...
Go语言爬虫系列教程(三)HTML解析技术
第3课:HTML解析技术 在上一章中,我们使用正则表达式提取网页内容,但这种方法有局限性。对于复杂的HTML结构,我们需要使用专门的HTML解析库。下面将介绍如何在Go中解析HTML。 1. HTML DOM树结构介绍 1.1 什么是DOM DOM…...

【三维重建】【3DGS系列】【深度学习】3DGS的理论基础知识之如何形成高斯椭球
【三维重建】【3DGS系列】【深度学习】3DGS的理论基础知识之如何形成高斯椭球 文章目录 【三维重建】【3DGS系列】【深度学习】3DGS的理论基础知识之如何形成高斯椭球前言高斯函数一维高斯多维高斯 椭球基本定义一般二次形式 3D高斯椭球3D高斯与椭球的关系各向同性(Isotropic)和…...
“夹子音”的发声原理和潜在风险
关于“夹子音”的发声原理和潜在风险,以下从科学角度和声乐实践出发,为你详细解析: 一、什么是夹子音? 夹子音是近年来网络流行的非专业术语,指通过刻意挤压喉部、改变共鸣腔形态发出的 尖细、嗲气、幼态化 的声音。常…...
思科硬件笔试面试题型解析
本专栏预计更新60期左右。当前第13期 这个系列通过在各类网上搜索大厂公开的笔试和面试题目,然后构造相关的知识点矩阵,让大家对核心的知识点有更深的认识,这个过程虽然耗时费力,但大厂的很多题目(包括模拟题)确实非常巧妙,很有代表性。由于官方没有发布过这样的题库,所…...

手写ES6 Promise() 相关函数
手写 Promise() 相关函数: Promise()、then()、catch()、finally() // 定义三种状态常量 const PENDING pending const FULFILLED fulfilled const REJECTED rejectedclass MyPromise {/*定义状态和结果两个私有属性:1.使用 # 语法(ES2022 官方私有字…...
Windows 平台 TCP 通信开发指南
开篇介绍 在 Windows 平台进行 TCP 通信开发,是网络编程中的常见需求。本文将详细讲解在 Windows 平台下,如何利用 Winsock API 实现高效的 TCP 客户端与服务端通信。 使用示例 必须引入的头文件 #include <windows.h> #pragma comment(lib,&q…...

【NLP 76、Faiss 向量数据库】
压抑与痛苦,那些辗转反侧的夜,终会让我们更加强大 —— 25.5.20 Faiss(Facebook AI Similarity Search)是由 Facebook AI 团队开发的一个开源库,用于高效相似性搜索的库,特别适用于大规模向…...

软件名称:系统日志监听工具 v1.0
软件功能:一款基于 PyQt5 开发的 Windows 系统日志监听工具,适用于系统运维、网络管理、故障排查等场景,具备以下核心功能: 支持监听系统三大日志源:应用程序 / 系统 / 安全日志实时抓取新日志事件,自动滚…...

Spring AI 之结构化输出转换器
截至 2024 年 2 月 5 日,旧的 OutputParser、BeanOutputParser、ListOutputParser 和 MapOutputParser 类已被弃用,取而代之的是新的 StructuredOutputConverter、BeanOutputConverter、ListOutputConverter 和 MapOutputConverter 实现类。后者可直接替换前者,并提供相同的…...

Java虚拟机面试题:内存管理(上)
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…...

进程间通信I·匿名管道
目录 进程间通信(IPC) 含义 目的 分类 匿名管道 原理 创建过程 特性 四大情况 close问题 代码练习 简单通信 进程池 小知识 进程间通信(IPC) 含义 就是让不同的进程能看到同一份资源,实现数据交流。 …...

Ubuntu Linux系统的基本命令详情
1.Ubuntu Linux是以桌面应用为主的Linux发行版操作系统 2.Ubuntu的用户使用 在登录系统一般使用在安装系统时建立的普通用户登录,如果要使用超级用户权限 #sudo ---执行命令 sudo passwd ---修改用户密码 su - root ---切换超级用户 系统的不同,命令也不…...

大数据治理:理论、实践与未来展望(二)
书接上文 文章目录 七、大数据治理的未来发展趋势(一)智能化与自动化(二)数据隐私与安全的强化(三)数据治理的云化(四)数据治理的跨行业合作(五)数据治理的生…...

PCB布局设计
PCB布局设计 一、原理图到PCB转换前的准备工作 在将原理图转换为PCB之前,我们需要进行一系列准备工作,确保设计的正确性和完整性。这一步骤至关重要,可以避免后续PCB设计中出现不必要的错误。 // 原理图转PCB前必要检查步骤 // 1. 仔细检查…...
【49. 字母异位词分组】
Leetcode算法练习 笔记记录 49. 字母异位词分组 49. 字母异位词分组 public List<List<String>> groupAnagrams(String[] strs) {Map<String, List<String>> map new HashMap<>();for (int i 0; i < strs.length; i) {//排序就是相同字符了…...
用 AI 让学习更懂你:如何打造自动化个性化学习系统?
用 AI 让学习更懂你:如何打造自动化个性化学习系统? 在这个信息爆炸的时代,传统的学习方式已经难以满足个体化需求。过去,我们依赖固定的教学课程,所有学生按照统一进度进行学习,但每个人的学习节奏、兴趣点和理解方式都不尽相同。而人工智能(AI)正在彻底改变这一局面…...

esp32+IDF V5.1.1版本编译freertos报错
error: portTICK_RATE_MS undeclared (first use in this function); did you mean portTICK_PERIOD_MS 解决方法: 使用命令 idf.py menuconfig 打开配置界面配置freeRtos 使能configENABLE_BACKWARD_COMPATIBLITY...
嵌入式软件-如何做好一份技术文档?
嵌入式软件-如何做好一份技术文档? 文章目录 嵌入式软件-如何做好一份技术文档?一.技术文档的核心价值与挑战二.文档体系的结构化设计三.精准表达嵌入式特有概念四. **像管理代码一样管理文档**,代码与文档的协同维护五.质量评估与持续改进5.…...

笔记本6GB本地可跑的图生视频项目(FramePack)
文章目录 (一)简介(二)本地执行(2.1)下载(2.2)更新(2.3)运行(2.4)生成 (三)注意(3.1)效…...

SpringMVC实战:动态时钟
引言 在现代 Web 开发中,选择一个合适的框架对于项目的成功至关重要。Spring MVC 作为 Spring 框架的核心模块之一,以其清晰的架构、强大的功能和高度的可配置性,成为了 Java Web 开发领域的主流选择。本文将通过一个“动态时钟”的实战项目…...
vscode include总是报错
VSCode 的 C/C 扩展可以通过配置 c_cpp_properties.json 来使用 compile_commands.json 文件中的编译信息,包括 include path、编译选项等。这样可以确保 VSCode 的 IntelliSense 与实际编译环境保持一致。 方法一:直接指定 compile_commands.json 路径…...

哈希表的实现(上)
前言 在C98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好的查询是,进行很少的比较次数就能够将…...

【Java高阶面经:微服务篇】1.微服务架构核心:服务注册与发现之AP vs CP选型全攻略
一、CAP理论在服务注册与发现中的落地实践 1.1 CAP三要素的技术权衡 要素AP模型实现CP模型实现一致性最终一致性(Eureka通过异步复制实现)强一致性(ZooKeeper通过ZAB协议保证)可用性服务节点可独立响应(支持分区存活)分区期间无法保证写操作(需多数节点可用)分区容错性…...