第四章 操作系统基础 —— 管理资源的管家
4.1 进程与线程
进程:资源分配的基本单位,拥有独立的内存空间。线程:CPU 调度的基本单位,共享进程资源。
// Java 创建线程的两种方式
// 方式1:继承 Thread
class MyThread extends Thread {
public void run() {
System.out.println("Thread running: " + Thread.currentThread().getName());
}
}
// 方式2:实现 Runnable
class MyRunnable implements Runnable {
public void run() {
System.out.println("Runnable running: " + Thread.currentThread().getName());
}
}
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
MyThread t1 = new MyThread();
t1.start();
Thread t2 = new Thread(new MyRunnable());
t2.start();
// 使用 Lambda
Thread t3 = new Thread(() -> {
System.out.println("Lambda thread");
});
t3.start();
// 等待线程结束
t1.join();
t2.join();
t3.join();
}
}
进程间通信(IPC)方式: 管道、消息队列、共享内存、Socket、信号量。
# Python 多进程(绕过 GIL)
from multiprocessing import Process, Queue
import os
def worker(q, name):
q.put(f"Hello from {name}, PID={os.getpid()}")
if __name__ == "__main__":
q = Queue()
processes = []
for i in range(4):
p = Process(target=worker, args=(q, f"Process-{i}"))
p.start()
processes.append(p)
for p in processes:
p.join()
while not q.empty():
print(q.get())
4.2 并发与锁
多个线程访问共享资源时会出现竞态条件,需要同步机制。
// 银行转账竞态条件演示
class BankAccount {
private int balance = 1000;
// 不加 synchronized 会出现数据不一致
public void withdraw(int amount) {
if (balance >= amount) {
// 模拟耗时操作,增加线程切换概率
try { Thread.sleep(10); } catch (InterruptedException e) {}
balance -= amount;
}
}
public int getBalance() { return balance; }
}
public class RaceConditionDemo {
public static void main(String[] args) throws InterruptedException {
BankAccount account = new BankAccount();
Runnable task = () -> {
for (int i = 0; i < 100; i++) {
account.withdraw(10);
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start(); t2.start();
t1.join(); t2.join();
// 预期余额 1000 - 2000 = -1000(但实际可能不同)
System.out.println("Balance: " + account.getBalance());
}
}
// 修复:使用 synchronized 或 ReentrantLock
public synchronized void withdraw(int amount) { ... }
死锁(Deadlock):两个线程互相等待对方释放资源。
// 经典死锁示例
public class DeadlockDemo {
private static final Object lock1 = new Object();
private static final Object lock2 = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (lock1) {
System.out.println("Thread1: 持有 lock1");
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("Thread1: 等待 lock2");
synchronized (lock2) {
System.out.println("Thread1: 获得 lock2");
}
}
});
Thread t2 = new Thread(() -> {
synchronized (lock2) {
System.out.println("Thread2: 持有 lock2");
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println("Thread2: 等待 lock1");
synchronized (lock1) {
System.out.println("Thread2: 获得 lock1");
}
}
});
t1.start(); t2.start();
// 程序卡住,不会打印后续信息
}
}
避免死锁的方法: 固定加锁顺序、使用超时锁、使用 tryLock。
4.3 内存管理 —— 虚拟内存与分页
操作系统通过虚拟内存让每个进程认为自己拥有连续的内存空间,实际映射到物理内存和磁盘。
// 演示页错误(Page Fault)
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
int main() {
// 分配大数组(超过物理内存)
size_t size = 1024 * 1024 * 1024L; // 1GB
int *arr = (int*)malloc(size);
if (!arr) {
printf("分配失败\n");
return 1;
}
struct timeval start, end;
gettimeofday(&start, NULL);
// 首次访问会触发大量缺页中断(慢)
for (size_t i = 0; i < size / sizeof(int); i += 4096) {
arr[i] = i;
}
gettimeofday(&end, NULL);
long elapsed = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
printf("首次写入耗时: %ld 微秒\n", elapsed);
// 第二次访问,数据已在内存(快)
gettimeofday(&start, NULL);
for (size_t i = 0; i < size / sizeof(int); i += 4096) {
arr[i] = i;
}
gettimeofday(&end, NULL);
elapsed = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
printf("第二次写入耗时: %ld 微秒\n", elapsed);
free(arr);
return 0;
}
4.4 文件系统
文件系统管理持久存储,常见类型:ext4、NTFS、APFS。
文件路径与权限:
# Linux 文件权限示例
-rwxr-xr-- 1 user group 1234 May 30 10:00 script.sh
# 第1位:-普通文件 d目录 l链接
# 2-4位:所有者权限 rwx
# 5-7位:组权限 r-x
# 8-10位:其他用户权限 r--
# 修改权限
chmod 755 script.sh # 所有者全权,组和其他读+执行
chmod u+x script.sh # 给所有者加执行权限
# Python 操作文件系统
import os
import shutil
# 创建目录
os.makedirs("test_dir/sub_dir", exist_ok=True)
# 列出文件
for item in os.listdir("."):
print(item)
# 递归遍历
for root, dirs, files in os.walk("."):
for file in files:
print(os.path.join(root, file))
# 复制
shutil.copy("src.txt", "dst.txt")
# 移动/重命名
shutil.move("old.txt", "new.txt")
# 删除
os.remove("temp.txt")
shutil.rmtree("test_dir")