进程和线程
进程是资源分配的基本单位,线程是CPU调度的基本单位。 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。
临界资源
原语 (Primitive)
指在操作系统或并发编程中,一种不可分割的操作或指令。原语在执行过程中不能被中断,必须作为一个整体完成,以确保操作的完整性和正确性。原语通常用于实现同步机制,如互斥锁、信号量等。
管程 (Monitor)
特点
- 互斥访问: 确保任何时刻只有一个线程访问管程中的共享数据。
- 条件变量: 用于线程同步,允许线程在某些情况下等待,直到某些条件满足。
- 线程安全: 程序员不必再手动管理锁和条件变量
使用Go语言的包实现管程, example:
go
package main
import (
"fmt"
"sync"
"time"
)
var (
condition = false
mutex = sync.Mutex
cond = sync.NewCond(&mutex) // 创建一个条件变量
)
func waitCondition() {
mutex.Lock() // 获取锁
for !condition {
cond.Wait() // 等待条件变量满足
}
fmt.Println("Condition met, proceeding...")
mutex.Unlock()
}
func setCondition() {
mutex.Lock() // 获取锁
condition = true
cond.Broadcast() // 通知所有等待的线程
mutex.Unlock() // 释放锁
}
func main() {
go waitCondition()
time.Sleep(1 * time.Second) // 模拟一些工作
setCondition()
time.Sleep(1 * time.Second) // 等待线程完成
}
/**
sync.NewCond(&mutex)
*/
死锁 (Deadlock)
死锁是指两个或多个进程在执行过程中,因争夺资源而造成的一种僵局(Deadly Embrace),若无外力作用,这些进程将无法继续执行
处理办法
预防死锁: 通过破坏四个必要条件之一, 就可以避免死锁的发生。
- 互斥: 一个资源只能被一个进程使用, 其他进程必须等待。
- 请求和保持条件: 一个进程占有资源后, 在请求其他资源, 保持已分配的资源。
- 不可抢占: 一个进程不能抢占其他进程的资源, 只能等它完成后主动释放资源。
- 循环等待条件:存在一个进程资源的循环链,每个进程都在等待下一个进程所持有的资源。
避免死锁: 避免死锁的发生, 例如使用互斥锁、信号量等机制来确保资源的互斥访问。
避免死锁的发生, 例如使用互斥锁、信号量等机制来确保资源的互斥访问。
检测与解除死锁:允许系统进入死锁状态,但定期检测死锁的发生,并采取措施解除死锁。
死锁与安全状态的关系
- 安全状态:系统能够按照某种顺序分配资源,确保所有进程都能完成,而不发生死锁。
- 不安全状态:系统无法保证所有进程都能完成,可能陷入死锁状态。
- 死锁状态(Deadlock State):系统已经陷入无法继续执行的僵局,所有进程都在等待资源,无法继续执行。
信号量 (Semaphore)
- wait(也称为P操作)
尝试获取资源, 如果信号量的值大于0,则将其减1并继续执行;如果信号量的值小于或等于0,则当前进程会被阻塞,并加入到阻塞队列中。
go
func wait(S) {
S.value--
if S.value < 0 {
// 将当前进程加入阻塞队列
block(S.queue)
}
}
- signal(也称为V操作)。
释放资源。如果阻塞队列中有进程等待资源,则唤醒其中一个进程;否则,将信号量的值加1。
为负就是阻塞;
go
func signal(S) {
S.value++
if S.value <= 0 {
// 从阻塞队列中唤醒一个进程
wakeup(S.queue)
}
}
使用场景
- 互斥: 多个线程需要访问同一个资源, 但只有一个线程可以访问该资源, 其他线程需要等待。
go
var mutex = &sync.Mutex{}
func criticalSection() {
mutex.Lock()
// 临界区代码
mutex.Unlock()
}
PCB(Process Control Block)
- 资源管理
使用计数信号量(初始值为可用资源的数量)来管理有限数量的资源。
调度算法:
- 先到先服务(FCFS, First-Come, First-Served):按照进程到达的时间顺序进行调度。 平均等待时间较长,可能导致“饥饿”现象。
- 短作业优先(SJF, Shortest Job First):选择等待时间最短的进程进行调度。 平均等待时间较短,但可能导致饥饿现象。
- 优先级调度:根据进程的优先级进行调度。 能导致低优先级进程“饥饿”。
- 时间片轮转(RR, Round Robin):每个进程被分配一个固定长度的时间片,时间片用完后,进程被放回就绪队列,等待下一次调度。 优点:公平性好,适合分时系统。
- 多级反馈队列调度(MFQ, Multilevel Feedback Queue):多个队列,每个队列有不同的优先级和时间片长度。进程在不同队列之间移动,根据其行为调整优先级。
系统
- 分时系统(Time-Sharing System): 多个用户共享一个计算机系统, 每个用户轮流使用计算机系统, 每个用户在计算机系统中占用的时间片段称为一个时间片。
用户较多的时候, 系统的响应速度会变慢。
- 实时系统(Real-Time System): 要求系统在规定的时间内完成规定的任务, 否则系统将自动采取措施, 以保证系统的安全性和可靠性。
实时系统通常不强调广泛的交互性能,而是注重快速响应和高可靠性。
- 批处理系统(Batch Processing System): 批处理系统是一种将多个作业(任务)成批提交给计算机处理的系统。系统按照提交的顺序依次处理每个作业,用户无法实时与系统进行交互。
无法实时交互的批处理系统, 通常使用批处理系统来处理实时任务。
- 多道程序设计(Multiprogramming): 多道程序设计是指在计算机系统中同时运行多个程序, 每个程序称为一个进程。