burpow
第13节-线程是什么

第13节-线程是什么

第 13 节:线程是什么

所属课程:操作系统自学路线:面向网络安全、逆向工程与漏洞分析
所属周次:第 7 周
课程主题:线程与并发
本节目标:理解线程的基本概念,掌握进程和线程的区别,知道一个进程内多个线程共享什么、各自私有什么,并能用 Linux pthread 和 Windows 工具观察线程行为。


1. 本节课你要学会什么

学完这一节,你应该能回答下面几个问题:

  1. 线程是什么?
  2. 进程和线程有什么区别?
  3. 一个进程里的多个线程共享哪些资源?
  4. 每个线程私有哪些资源?
  5. 线程为什么比进程更轻量?
  6. 什么是线程栈?
  7. Linux 下 pthread 是什么?
  8. Windows 下 Thread 是什么?
  9. 如何观察一个进程中的多个线程?
  10. 为什么恶意代码和系统程序经常创建线程?

本节课的主线是:

1
进程提供资源容器 -> 线程作为执行流 -> 多个线程共享进程资源 -> 每个线程有自己的执行上下文和栈

上一周我们学习了进程,这一节开始理解进程内部的多个执行流。


2. 为什么需要线程

如果只有进程,也可以完成很多任务。

例如:

  • 一个进程处理用户输入
  • 一个进程处理文件读写
  • 一个进程处理网络请求

但是进程之间隔离较强,创建和切换成本较高。

很多时候,我们希望一个程序内部同时做多件事。

例如浏览器:

  • 一个线程负责 UI 响应
  • 一个线程负责网络请求
  • 一个线程负责渲染页面
  • 一个线程负责 JavaScript 执行
  • 一个线程负责磁盘缓存

再例如服务器:

  • 主线程监听端口
  • 工作线程处理客户端请求
  • 后台线程写日志或清理资源

这时线程就很有用。

线程让同一个进程内部可以有多个执行流。


3. 线程是什么

线程英文是:

1
Thread

可以先这样理解:

线程是进程中的一条执行流。

一个进程至少有一个线程。

这个线程通常叫:

1
主线程

进程可以创建更多线程。

例如:

1
2
3
4
5
进程 A
├── 主线程
├── 工作线程 1
├── 工作线程 2
└── 后台线程

这些线程运行在同一个进程中,共享进程的大部分资源。


4. 进程和线程的关系

可以把进程理解成资源容器,把线程理解成执行单位。

简化理解:

1
2
进程:资源分配的单位
线程:CPU 调度执行的单位

一个进程拥有:

  • 地址空间
  • 打开的文件
  • 权限信息
  • 环境变量
  • 当前工作目录
  • 代码和数据

线程使用这些资源来执行代码。

如果没有线程,进程里的代码就没有执行流。


5. 进程和线程的区别

对比项 进程 线程
资源拥有 拥有独立地址空间和资源 共享所属进程资源
创建成本 较高 较低
切换成本 较高 较低
隔离性
通信方式 需要 IPC,如管道、socket、共享内存 可直接共享变量
崩溃影响 一个进程崩溃通常不直接影响其他进程 一个线程崩溃通常导致整个进程崩溃
典型用途 程序实例、服务隔离 并发任务、后台工作

这张表很重要。

安全分析中,你经常需要判断:

1
某个行为发生在哪个进程?哪个线程?

6. 多线程共享什么

同一个进程中的多个线程通常共享:

  • 代码段
  • 全局变量
  • 打开的文件描述符或句柄
  • 当前工作目录
  • 环境变量
  • 进程权限
  • 地址空间
  • 动态库映射

例如全局变量:

1
int counter = 0;

如果多个线程同时访问 counter,它们访问的是同一个变量。

这既方便,也危险。

方便在于线程间通信简单。

危险在于如果没有同步,可能产生竞态条件。

下一节会专门讲同步、竞争和死锁。


7. 每个线程私有什么

虽然线程共享进程资源,但每个线程也有自己的东西。

每个线程通常私有:

  • 线程 ID
  • 寄存器上下文
  • 指令指针 RIP/EIP
  • 栈指针 RSP/ESP
  • 自己的线程栈
  • 线程局部存储 TLS
  • 调度状态
  • errno 等部分线程局部数据

最重要的是:

1
每个线程有自己的栈和寄存器上下文。

这意味着不同线程可以同时执行不同函数,拥有各自的局部变量和调用栈。


8. 线程栈是什么

上一节我们学过函数调用和栈帧。

每个线程都有自己的调用栈。

例如一个进程有三个线程:

1
2
3
4
5
6
7
8
9
进程地址空间
+------------------------+
| 代码段 | 共享
| 全局变量 | 共享
| 堆 | 共享
| 线程 1 栈 | 私有
| 线程 2 栈 | 私有
| 线程 3 栈 | 私有
+------------------------+

线程 1 可以正在执行:

1
main -> handle_input

线程 2 可以正在执行:

1
worker -> process_task

线程 3 可以正在执行:

1
logger -> write_log

它们的调用栈互不相同。


9. 多线程为什么容易出问题

多线程强大,但复杂。

主要原因是:

1
多个线程共享内存,并且执行顺序不确定。

例如:

1
counter++;

看起来是一句代码。

但底层可能包含:

1
2
3
读取 counter
加 1
写回 counter

如果两个线程同时执行,可能发生:

1
2
3
4
线程 A 读取 counter = 0
线程 B 读取 counter = 0
线程 A 写回 1
线程 B 写回 1

结果本来应该是 2,实际却是 1。

这就是竞态条件。

下一节会深入讲。


10. 用户级线程和内核级线程

线程可以从不同层次理解。

10.1 用户级线程

用户级线程由用户态库管理。

优点:

  • 创建和切换快
  • 不一定每次进入内核

缺点:

  • 如果内核不知道这些线程,调度和阻塞处理会受限制

10.2 内核级线程

内核级线程由操作系统内核管理和调度。

现代主流系统中的线程通常会映射到内核可调度实体。

Linux 中,线程和进程在内核实现上关系很近。

Linux 的线程创建底层常和 clone 系统调用有关。


11. Linux 中的线程

Linux 下常用 pthread 编写多线程程序。

pthread 是:

1
POSIX Threads

常见函数:

1
2
3
4
5
6
pthread_create
pthread_join
pthread_exit
pthread_self
pthread_mutex_lock
pthread_mutex_unlock

创建线程的典型模式:

1
2
3
pthread_t t;
pthread_create(&t, NULL, worker, NULL);
pthread_join(t, NULL);

含义:

1
2
创建一个线程执行 worker 函数
主线程等待这个线程结束

12. 第一个 pthread 程序

创建 thread_demo.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

void* worker(void* arg) {
printf("worker thread: pid=%d tid-like=%lu\n", getpid(), pthread_self());
return NULL;
}

int main() {
pthread_t t;

printf("main thread: pid=%d tid-like=%lu\n", getpid(), pthread_self());

pthread_create(&t, NULL, worker, NULL);
pthread_join(t, NULL);

return 0;
}

编译:

1
gcc thread_demo.c -o thread_demo -pthread

运行:

1
./thread_demo

你会看到:

1
2
main thread: pid=...
worker thread: pid=...

注意:

两个线程的 pid 一样。

因为它们属于同一个进程。


13. pthread_create 参数解释

pthread_create 原型大致是:

1
2
3
4
5
6
int pthread_create(
pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg
);

参数含义:

参数 含义
thread 用于保存新线程 ID
attr 线程属性,NULL 表示默认属性
start_routine 新线程要执行的函数
arg 传给线程函数的参数

线程函数通常长这样:

1
2
3
void* worker(void* arg) {
return NULL;
}

为什么参数和返回值都是 void*

因为这样可以传递任意类型指针。


14. pthread_join 是什么

pthread_join 用于等待线程结束。

例如:

1
pthread_join(t, NULL);

意思是:

1
主线程等待线程 t 执行结束

如果不 join,主线程可能先退出。

进程一旦退出,其他线程通常也会被结束。

所以创建线程后,经常需要 pthread_join 等待它完成。

也可以创建 detached thread,但入门阶段先掌握 join 模式。


15. 给线程传参数

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <pthread.h>
#include <stdio.h>

void* worker(void* arg) {
int id = *(int*)arg;
printf("worker id=%d\n", id);
return NULL;
}

int main() {
pthread_t t;
int id = 1;

pthread_create(&t, NULL, worker, &id);
pthread_join(t, NULL);

return 0;
}

这里传给线程的是 id 的地址。

注意:

线程拿到的是指针。

如果主线程中这个变量生命周期结束,或者多个线程共享同一个变量地址,可能导致问题。

例如在循环里创建多个线程时,常见错误是把同一个循环变量地址传给所有线程。


16. 创建多个线程

创建 multi_thread_demo.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <pthread.h>
#include <stdio.h>

#define N 4

void* worker(void* arg) {
int id = *(int*)arg;
printf("worker %d running\n", id);
return NULL;
}

int main() {
pthread_t threads[N];
int ids[N];

for (int i = 0; i < N; i++) {
ids[i] = i;
pthread_create(&threads[i], NULL, worker, &ids[i]);
}

for (int i = 0; i < N; i++) {
pthread_join(threads[i], NULL);
}

return 0;
}

编译运行:

1
2
gcc multi_thread_demo.c -o multi_thread_demo -pthread
./multi_thread_demo

你可能发现输出顺序不固定。

例如:

1
2
3
4
worker 1 running
worker 3 running
worker 0 running
worker 2 running

这说明线程调度顺序不由你直接控制。


17. 线程调度顺序不确定

多线程程序中,线程执行顺序通常是不确定的。

操作系统调度器会根据:

  • CPU 核心数量
  • 时间片
  • 优先级
  • I/O 等待
  • 系统负载
  • 调度策略

决定哪个线程运行。

所以不要写依赖特定线程执行顺序的代码。

如果线程之间需要顺序或互斥,需要使用同步机制。

下一节会讲:

  • mutex
  • semaphore
  • condition variable
  • deadlock
  • race condition

18. 用 ps 观察线程

运行一个睡眠中的多线程程序。

创建 thread_sleep_demo.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

void* worker(void* arg) {
int id = *(int*)arg;
printf("worker %d start\n", id);
sleep(30);
return NULL;
}

int main() {
pthread_t t1, t2;
int id1 = 1;
int id2 = 2;

printf("pid=%d\n", getpid());

pthread_create(&t1, NULL, worker, &id1);
pthread_create(&t2, NULL, worker, &id2);

sleep(30);

pthread_join(t1, NULL);
pthread_join(t2, NULL);
return 0;
}

编译运行:

1
2
gcc thread_sleep_demo.c -o thread_sleep_demo -pthread
./thread_sleep_demo

另开终端:

1
ps -T -p <pid>

-T 可以显示线程。

你会看到同一个进程下多个线程。


19. 用 /proc 观察线程

Linux 下可以查看:

1
ls /proc/<pid>/task

这里会列出该进程中的线程 ID。

每个线程在 /proc/<pid>/task/<tid> 下都有自己的状态信息。

例如:

1
cat /proc/<pid>/task/<tid>/status

你可以看到:

  • Name
  • State
  • Tgid
  • Pid
  • PPid
  • Threads

其中:

1
2
Tgid 通常是线程组 ID,也常对应进程 ID
Pid 在 task 中可能表示具体线程 ID

Linux 中线程和进程在内核实现上非常接近,这也是为什么 /proc/<pid>/task 很重要。


20. 用 strace 观察线程创建

对 pthread 程序执行:

1
strace -f ./thread_demo

你可能看到:

1
clone(...)

在 Linux 中,pthread 创建线程底层常使用 clone 系统调用。

clone 可以通过不同 flags 控制共享哪些资源。

线程创建时会共享:

  • 地址空间
  • 文件描述符表
  • 信号处理等

所以从系统调用角度看,线程和进程创建都可能和 clone 有关,只是 flags 不同。


21. Windows 中的线程

Windows 中,进程也包含一个或多个线程。

常见 API:

1
2
3
4
5
6
7
CreateThread
CreateRemoteThread
ExitThread
WaitForSingleObject
GetCurrentThreadId
SuspendThread
ResumeThread

Windows 线程也有:

  • Thread ID
  • 寄存器上下文
  • TLS
  • 优先级
  • 状态

进程启动时,Windows 会创建主线程。

程序可以继续创建其他线程执行任务。


22. Windows 线程和逆向

Windows 逆向中,经常会看到:

1
2
3
4
5
CreateThread
_beginthreadex
CreateRemoteThread
QueueUserAPC
NtCreateThreadEx

这些都和线程执行有关。

其中:

1
CreateRemoteThread

尤其值得注意。

因为它可以在另一个进程中创建线程。

在恶意代码分析中,CreateRemoteThread 常和进程注入相关。

当然,合法软件也可能使用远程线程技术,但需要结合上下文分析。


23. Windows 工具观察线程

可以用 Process Explorer:

  1. 找到目标进程
  2. 双击打开属性
  3. 切换到 Threads 标签
  4. 查看线程列表

你可以看到:

  • TID
  • Start Address
  • CPU 使用
  • 状态
  • 调用栈,若符号可用

x64dbg 中也能查看线程窗口。

当调试多线程程序时,你可以:

  • 切换当前线程
  • 暂停某个线程
  • 查看不同线程的寄存器
  • 查看不同线程的栈

这对分析多线程恶意代码很重要。


24. 线程和全局变量共享实验

创建 thread_global_demo.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <pthread.h>
#include <stdio.h>

int global_counter = 0;

void* worker(void* arg) {
global_counter += 1;
printf("worker: global_counter=%d\n", global_counter);
return NULL;
}

int main() {
pthread_t t1, t2;

pthread_create(&t1, NULL, worker, NULL);
pthread_create(&t2, NULL, worker, NULL);

pthread_join(t1, NULL);
pthread_join(t2, NULL);

printf("main: global_counter=%d\n", global_counter);
return 0;
}

编译运行:

1
2
gcc thread_global_demo.c -o thread_global_demo -pthread
./thread_global_demo

你会看到多个线程都能访问同一个全局变量。

但这个程序还没有正确同步。

如果循环次数增加,就可能出现竞态问题。


25. 线程和局部变量

每个线程有自己的栈,所以线程函数中的局部变量通常在该线程自己的栈上。

例如:

1
2
3
4
5
void* worker(void* arg) {
int local_var = 123;
printf("local_var addr=%p\n", &local_var);
return NULL;
}

如果多个线程运行这个函数,每个线程的 local_var 地址通常不同。

实验:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <pthread.h>
#include <stdio.h>

void* worker(void* arg) {
int local_var = 123;
printf("thread local_var addr=%p\n", &local_var);
return NULL;
}

int main() {
pthread_t t1, t2;
int main_local = 456;

printf("main local addr=%p\n", &main_local);

pthread_create(&t1, NULL, worker, NULL);
pthread_create(&t2, NULL, worker, NULL);

pthread_join(t1, NULL);
pthread_join(t2, NULL);
return 0;
}

观察不同线程局部变量地址。


26. 线程和堆共享

堆属于进程地址空间。

所以多个线程共享同一个堆。

一个线程 malloc 出来的内存,另一个线程理论上也可以访问,只要它拿到了指针。

这很方便,但也很危险。

如果一个线程释放了堆内存,另一个线程还继续使用这个指针,就可能产生:

1
Use-After-Free

多线程环境下,UAF 和竞态条件常常结合出现。

这在真实漏洞中很常见。


27. 线程和文件描述符共享

同一个进程内的线程共享文件描述符表。

如果一个线程打开文件:

1
int fd = open("test.txt", O_WRONLY);

另一个线程如果能访问到 fd 变量,也可以写这个文件。

如果多个线程同时写同一个文件描述符,输出可能交错。

这也是为什么日志系统、多线程文件写入需要同步机制。


28. 线程和信号的复杂性

Linux 中信号和线程的关系比较复杂。

例如:

  • 信号可能发送给进程
  • 也可能发送给指定线程
  • 每个线程有自己的信号掩码
  • 某些信号会导致整个进程终止

入门阶段不需要深入信号细节。

只需要知道:

1
多线程程序中,异常、信号、崩溃可能影响整个进程。

如果某个线程发生段错误,通常整个进程都会崩溃。


29. 线程为什么比进程轻量

线程比进程轻量,主要因为它们共享进程资源。

创建新进程通常需要:

  • 创建新的地址空间
  • 建立独立资源结构
  • 复制或设置文件描述符
  • 设置更多进程级状态

创建线程通常不需要新的独立地址空间。

它只需要:

  • 创建线程控制结构
  • 分配线程栈
  • 设置寄存器上下文
  • 加入调度队列

所以线程创建和切换通常比进程更轻。

但代价是隔离性更弱,更容易互相影响。


30. 多线程和性能

多线程不一定让程序更快。

它适合:

  • I/O 密集任务
  • 多核 CPU 上可并行计算的任务
  • UI 和后台任务分离
  • 服务器并发请求处理

但多线程也有成本:

  • 线程创建成本
  • 上下文切换成本
  • 锁竞争
  • 缓存一致性开销
  • 调试复杂度
  • 死锁和竞态风险

所以不要为了“看起来高级”随便使用多线程。


31. 线程和逆向工程

逆向多线程程序时,要注意:

  • 哪个线程创建了哪个线程
  • 线程入口函数在哪里
  • 每个线程负责什么任务
  • 是否有后台线程
  • 是否有定时线程
  • 是否有反调试线程
  • 是否有网络通信线程
  • 是否有监控或自保护线程

有些程序主线程看起来很简单,真正逻辑在工作线程中。

所以动态调试时,要观察线程列表。

在 x64dbg 中,如果程序突然创建新线程,要关注线程入口地址。


32. 线程和漏洞分析

多线程程序容易出现并发漏洞。

常见包括:

  • 竞态条件
  • TOCTOU
  • Use-After-Free
  • Double Free
  • 数据竞争
  • 死锁
  • 锁顺序错误

例如:

1
2
3
线程 A 检查对象仍然有效
线程 B 释放对象
线程 A 继续使用对象

这可能导致 UAF。

又例如:

1
2
3
线程 A 检查文件权限
线程 B 替换文件路径
线程 A 打开错误文件

这可能导致 TOCTOU 问题。

下一节会重点讲同步和竞态。


33. 线程和恶意代码分析

恶意代码经常创建线程。

常见用途:

  • 主线程继续运行,后台线程执行恶意逻辑
  • 一个线程负责网络通信
  • 一个线程负责监控分析工具
  • 一个线程负责解密或解包
  • 一个线程负责持久化
  • 一个线程负责注入或执行 payload
  • 一个线程负责延迟执行

如果只看主线程,可能漏掉关键行为。

分析时要关注:

  • 线程创建 API
  • 线程入口地址
  • 线程开始后调用哪些 API
  • 是否创建远程线程
  • 是否有长时间 sleep
  • 是否有监控调试器的线程

34. Linux 实验:pthread 基础

thread_demo.c 并运行:

1
2
gcc thread_demo.c -o thread_demo -pthread
./thread_demo

然后用:

1
strace -f ./thread_demo

观察是否出现 clone

提交时记录:

1
2
3
4
5
1. 主线程输出
2. 工作线程输出
3. 两个线程 PID 是否相同
4. strace 中是否出现 clone
5. pthread_create 和 clone 的关系

35. Linux 实验:观察线程列表

运行 thread_sleep_demo

另开终端:

1
2
ps -T -p <pid>
ls /proc/<pid>/task

提交内容:

1
2
3
4
5
1. 进程 PID
2. 看到几个线程
3. 每个线程的 TID
4. /proc/<pid>/task 中有哪些目录
5. 为什么同一进程下会有多个线程 ID

36. Linux 实验:观察线程栈地址

运行局部变量地址实验。

提交内容:

1
2
3
4
5
1. 主线程局部变量地址
2. 线程 1 局部变量地址
3. 线程 2 局部变量地址
4. 这些地址是否相同
5. 这说明每个线程有什么私有资源

37. Windows 实验:Process Explorer 观察线程

如果你有 Windows 环境:

  1. 打开 Process Explorer
  2. 选择一个进程,例如 notepad 或自己写的程序
  3. 双击进入属性
  4. 打开 Threads 标签
  5. 查看线程列表

记录:

1
2
3
4
5
6
1. 进程名
2. PID
3. 线程数量
4. 至少 3 个线程 ID
5. 线程 Start Address
6. 是否能看到线程 CPU 使用情况

38. Windows 实验:x64dbg 观察线程

用 x64dbg 打开一个程序。

练习:

  1. 打开 Threads 窗口
  2. 查看当前线程
  3. 设置断点
  4. 单步执行
  5. 如果程序创建新线程,观察线程列表变化
  6. 切换线程查看寄存器和栈

重点:

1
不同线程有不同 RIP/RSP,也就是不同执行位置和栈。

39. 本节重点总结

你需要记住这些核心结论:

  1. 线程是进程中的一条执行流。
  2. 一个进程至少有一个线程,也可以有多个线程。
  3. 进程更像资源容器,线程更像 CPU 调度执行单位。
  4. 同一进程内线程共享地址空间、堆、全局变量、文件描述符等资源。
  5. 每个线程有自己的线程 ID、寄存器上下文、指令位置和线程栈。
  6. 多线程输出顺序和执行顺序通常不确定。
  7. Linux 下常用 pthread 创建线程,底层常和 clone 有关。
  8. Windows 下常见线程 API 包括 CreateThreadCreateRemoteThread 等。
  9. 多线程程序容易出现竞态条件、UAF、死锁等问题。
  10. 逆向和恶意代码分析时,要关注线程创建和线程入口函数。

40. 本节课后作业

作业 1:第一个 pthread 程序

写并运行 thread_demo.c

提交内容:

1
2
3
4
5
6
1. 源代码
2. 主线程输出
3. 工作线程输出
4. 两个线程的 PID 是否相同
5. pthread_create 的作用是什么
6. pthread_join 的作用是什么

作业 2:多个线程输出顺序

写并运行 multi_thread_demo.c

运行 5 次。

提交内容:

1
2
3
4
1. 5 次运行输出
2. 输出顺序是否固定
3. 为什么线程执行顺序不确定
4. 如果需要固定顺序,应该使用什么机制

作业 3:观察线程列表

运行 thread_sleep_demo

执行:

1
2
ps -T -p <pid>
ls /proc/<pid>/task

提交内容:

1
2
3
4
5
1. 进程 PID
2. 线程数量
3. TID 列表
4. ps -T 的作用
5. /proc/<pid>/task 的作用

作业 4:线程共享全局变量

运行 thread_global_demo.c

提交内容:

1
2
3
4
1. 程序输出
2. 多个线程是否访问同一个 global_counter
3. 为什么这说明全局变量是共享的
4. 如果循环增加到大量次数,可能出现什么问题

作业 5:线程私有栈实验

运行线程局部变量地址程序。

提交内容:

1
2
3
4
5
1. 主线程局部变量地址
2. 工作线程 1 局部变量地址
3. 工作线程 2 局部变量地址
4. 这些地址是否不同
5. 每个线程为什么需要自己的栈

作业 6:Windows 线程观察

如果你有 Windows 环境,用 Process Explorer 或 x64dbg 观察线程。

提交内容:

1
2
3
4
5
6
1. 进程名
2. PID
3. 线程数量
4. 至少 3 个线程 ID
5. 是否能看到线程入口地址
6. 为什么线程入口地址对逆向分析有用

41. 自测题

题 1

线程是什么?

题 2

进程和线程有什么区别?

题 3

同一个进程中的多个线程共享哪些资源?

题 4

每个线程通常私有哪些资源?

题 5

为什么每个线程需要自己的栈?

题 6

pthread_createpthread_join 分别做什么?

题 7

为什么多线程程序执行顺序通常不确定?

题 8

Windows 中 CreateRemoteThread 为什么在安全分析中值得关注?

题 9

多线程程序中可能出现哪些安全问题?


42. 自测题参考答案

答 1

线程是进程中的一条执行流。一个进程至少有一个线程,也可以创建多个线程并发执行不同任务。

答 2

进程拥有独立地址空间和资源,隔离性较强;线程属于某个进程,多个线程共享进程资源,但每个线程有自己的执行上下文和栈。线程创建和切换通常比进程更轻量。

答 3

同一进程中的线程通常共享代码段、全局变量、堆、打开的文件描述符或句柄、当前工作目录、环境变量、权限信息、动态库映射和地址空间。

答 4

每个线程通常私有线程 ID、寄存器上下文、指令指针、栈指针、线程栈、线程局部存储和调度状态等。

答 5

因为不同线程可能同时执行不同函数调用链,需要各自保存局部变量、返回地址和调用栈信息,所以每个线程需要自己的栈。

答 6

pthread_create 用于创建新线程,并让新线程从指定函数开始执行;pthread_join 用于等待指定线程结束并回收相关资源。

答 7

因为线程由操作系统调度器根据 CPU、优先级、时间片、I/O 等因素决定运行顺序,程序不能假设线程按固定顺序执行。

答 8

因为 CreateRemoteThread 可以在其他进程中创建线程,常见于进程注入等行为。它不一定恶意,但在异常上下文中值得重点分析。

答 9

多线程程序可能出现竞态条件、TOCTOU、Use-After-Free、Double Free、数据竞争、死锁、锁顺序错误等问题。


43. 下一节预告

下一节课会讲:

1
同步、竞争和死锁

你会学习:

  • 什么是竞态条件
  • 为什么 counter++ 不是绝对安全的
  • mutex、semaphore、condition variable
  • 死锁四条件
  • TOCTOU 漏洞基本思想
  • 如何用实验观察加锁前后的差异
隐藏
换装
本文作者:burpow
本文链接:https://youthfulnesszxx.github.io/2026/05/28/第13节-线程是什么/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可