回顾:
- 调度器类型:抢占式/非抢占式,长期/中期/短期)
- 性能评价标准
- 调度算法:FCFS, SJF,轮询,优先队列
本章小结:
- 线程与进程
- 不同的线程实现
- POSIX线程(PThreads)
线程
从操作系统的角度看线程
一个进程由两个基本单元组成:
1. 资源:将所有相关资源分组在一起
- 包含进程映像(程序、数据、堆、栈)的逻辑地址空间。
- 文件,I/O设备,I/O通道,…
2. 执行轨迹,即一个被执行的实体
一个进程可以在多个执行轨迹之间共享其资源,即在同一资源环境中运行的多个线程
每个线程都有自己的执行上下文(例如程序计数器,堆栈,寄存器)
所有线程都可以访问进程的共享资源
- 例如文件,一个线程打开一个文件,同一进程的所有线程都可以访问该文件
- 全局变量,内存等(⇒同步!)
与进程类似,线程具有:
- 状态和转换(新建、运行、阻塞、就绪、终止)(new, running, blocked, ready, terminated)
- 线程控制块(TCB)
线程产生更少的创建/终止/切换开销(地址空间对于同一进程的线程保持相同)
一些cpu对多线程有直接的硬件支持:通常,每个内核最多可以提供8个硬件线程
线程间通信比进程间通信更容易/更快(线程默认共享内存)
地址空间中不需要保护边界(线程是合作的,属于同一个用户,并且有一个共同的目标)
必须仔细考虑同步!
为什么要使用线程
多个相关的活动应用于相同的资源,这些资源应该是可访问/共享的
进程通常包含多个阻塞任务
- I/O操作(线程阻塞,中断标志完成)
- 内存访问:页面错误导致阻塞
这些活动应并行/同时进行
应用实例:web服务器、制作程序、电子表格、文字处理器、处理大数据量
线程的操作系统实现
用户线程 User threads:多对一
线程管理(创建、销毁、调度、线程控制块操作)通过用户库在用户空间中完成
进程在内核不知情的情况下维护运行时系统管理的线程表
- 类似于过程表
- 用于线程切换
- 跟踪线程相关信息



优点:
- 线程位于用户空间(即,不需要模式切换)
- 对线程调度程序的完全控制
- 操作系统无关(线程可以在不支持它们的操作系统上运行)
缺点:
- 阻塞系统调用会挂起整个进程(用户线程被映射到单个进程,由内核管理)
- 没有真正的并行性(进程在单个CPU上调度)
- 时钟中断是不存在的(即用户线程是非抢占的)
- 页面错误导致进程阻塞
内核线程 Kernel Threads:一对一
内核管理线程,用户应用程序通过API和系统调用访问线程设施
- 线程表在内核中,包含线程控制块(进程控制块的子集)
- 如果一个线程阻塞,内核将从相同或不同的进程中选择线程
优点:
- 真正的并行是可以实现的
- 不需要运行期系统
频繁的模式切换会导致性能下降
Windows和Linux应用这种方法



混合实现 Hybrid Implementations:多对多
用户线程被复用到内核线程上
内核看到并调度内核线程(数量有限)
用户应用程序看到用户线程并创建/调度这些线程(数量不受限制)
性能对比: 用户线程vs内核线程vs进程
Null fork:创建、调度、运行和终止空进程/线程的开销
信号等待:同步线程的开销
线程管理:库(Libraries)
线程库提供了一个API/接口来管理线程。(例如,创建、运行、销毁、同步等)
线程库可以实现:
- 完全在用户空间中(即用户线程)
- 基于系统调用,即依赖内核进行线程实现
线程API的例子包括POSIX的PThreads, Windows Threads和Java Threads
- PThread规范可以作为用户线程或内核线程实现
POSIX Threads
也被称为Pthreads,是POSIX标准的一部分,定义了一套用于创建和操纵线程的API。 它为操作系统级线程提供了统一的接口,使得在多种UNIX-like系统上编写可移植的多线程程序成为可能。 Pthreads提供了一套丰富的API,包括创建线程、销毁线程、线程同步和线程通信等操作。 这些API在C语言中定义,因此对于使用C语言进行多线程编程的 开发者 来说非常方便。
POSIX 线程 (Pthread)
POSIX 线程是一种任何人都可以实现的规范,即它定义了一组 API(函数调用,超过 60 个)及其功能作用。
PThreads 的核心功能包括:
欲获取更详细的描述,请在命令行中使用“man function_name”命令。
这段C程序演示了如何使用POSIX线程(pthread)创建多个线程,每个线程打印自己的ID:
-
主线程创建10个子线程,每个线程接收自己的ID作为参数
-
每个子线程执行
hello函数,打印自己的ID -
主线程等待所有子线程结束
-
程序退出

#include语句:
-
pthread.h:提供多线程相关函数 -
stdio.h:标准输入输出
hello线程函数:
void* hello(void* arg) {
printf("Hello from thread %d\n", *((int*)arg));
return 0;
}
-
线程的入口函数,参数和返回值都是
void* -
将参数转换为
int*后解引用获取线程ID -
打印线程ID后返回0
创建线程的循环:
for(int i = 0; i < THREADS; i++) {
args[i] = i; // 设置线程参数
if(pthread_create(threads + i, NULL, hello, args + i)) {
printf("Creating thread %d failed\n", i);
return -1;
}
}
-
pthread_create参数:-
线程标识符的地址
-
线程属性(这里为NULL表示默认)
-
线程函数
-
传递给线程函数的参数
-
-
如果创建失败返回非零值,程序退出
等待线程结束的循环:
for(int i = 0; i < THREADS; i++)
pthread_join(threads[i], NULL);
-
pthread_join等待指定线程结束 -
第二个参数可以接收线程返回值(这里不需要设为NULL)
750

被折叠的 条评论
为什么被折叠?



