站内搜索

查找文章

Note

OS-Lab-Review

操作系统原理实验填空题背诵表

按实验题库章节整理,重点提取填空题中需要记忆的头文件、API、参数、固定宏与代码模板。


第一章 Linux 系统与实验环境

1. 内核源码目录

arch/      与硬件体系结构相关
kernel/    调度、定时器等内核核心代码
ipc/       System V IPC 等进程间通信代码
drivers/   设备驱动
mm/        内存管理
fs/        文件系统

Linux 内核五大子系统:

SCHED    进程调度
MM       内存管理
VFS      虚拟文件系统
NET      网络接口
IPC      进程间通信

2. 高频固定填空

Linux 版本:内核版、发行版
至少创建的分区:根分区、swap 分区
make 的规则文件:Makefile
程序请求内核服务的入口:系统调用

3. 常用命令

dmesg          # 查看内核环形缓冲区、启动信息
pstree         # 树状显示进程关系
top            # 动态显示进程、CPU、内存信息
uname -r       # 查看内核版本
pwd            # 显示当前目录
ps -f          # 完整格式显示进程信息
ps ax          # 显示较完整的进程列表
lsmod          # 显示已加载的内核模块
ipcs           # 查看 System V IPC 对象

4. GCC 参数

gcc test.c
# 默认生成:a.out

gcc test.c -o test
# -o:指定输出文件名

gcc thread.c -o thread -pthread
# -pthread:编译并链接 pthread 程序

第二章 进程控制与程序执行

1. 常用头文件

#include <unistd.h>     // fork、getpid、getppid、read、write、exec
#include <sys/wait.h>   // wait、waitpid
#include <fcntl.h>      // open、O_CREAT、O_TRUNC、O_RDWR
#include <sys/stat.h>   // S_IRWXU 等权限宏
#include <string.h>     // strcpy、strlen
#include <stdlib.h>     // exit、system
#include <errno.h>      // errno

2. fork()

pid_t pid = fork();

返回值必须背:

pid < 0    创建失败
pid == 0   当前是子进程
pid > 0    当前是父进程,pid 是子进程号

典型填空:

if ((cld_pid = fork()) == 0) {
    // 子进程
} else {
    // 父进程
}

3. 进程号 API

pid_t getpid(void);    // 获取当前进程 PID
pid_t getppid(void);   // 获取父进程 PID

典型代码:

printf("current PID = %d\n", getpid());
printf("parent PID = %d\n", getppid());
printf("child PID = %d\n", cld_pid);  // 父进程中 fork 的返回值

4. 等待子进程

pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);

常见填写:

wait(NULL);
wait(0);
waitpid(pid, NULL, 0);

参数:

pid       指定等待哪个子进程
status    保存退出状态;不需要时填 NULL
options   0 表示普通阻塞等待

5. 文件操作

int open(const char *path, int flags, mode_t mode);
ssize_t write(int fd, const void *buf, size_t count);
ssize_t read(int fd, void *buf, size_t count);
int close(int fd);

典型代码:

int fd = open(
    "temp",
    O_CREAT | O_TRUNC | O_RDWR,
    S_IRWXU
);

write(fd, buf, strlen(buf));
close(fd);

常见标志:

O_CREAT    文件不存在时创建
O_TRUNC    文件存在时清空
O_RDWR     以可读可写方式打开
S_IRWXU    文件所有者拥有读、写、执行权限

6. execsystem

execlp("ps", "ps", "-f", NULL);

char *argv[] = {"ls", "-l", NULL};
execvp(argv[0], argv);

system("ls -l");

记忆:

exec 成功:替换当前程序,后续代码不执行,PID 通常不变
system 成功:命令执行结束后返回原程序

7. fork() 数量固定题

连续执行 (n) 次无条件 fork()

最终进程数 = 2^n

题库固定结果:

for (i = 0; i < 2; i++) {
    fork();
    printf("a");
}
进程数:4
字符数:8
原因:未刷新的缓冲区也会被 fork 复制

使用换行或 fflush(stdout)

printf("a\n");

或:

printf("a");
fflush(stdout);
两次循环:4 个进程,输出 6 个 a

第三章 线程与同步

1. pthread 头文件与编译参数

#include <pthread.h>
gcc thread.c -o thread -pthread

2. 创建和等待线程

int pthread_create(
    pthread_t *tid,
    const pthread_attr_t *attr,
    void *(*start_routine)(void *),
    void *arg
);

int pthread_join(
    pthread_t tid,
    void **retval
);

典型填写:

pthread_t id1, id2;

pthread_create(&id1, NULL, thread_white_fun, NULL);
pthread_create(&id2, NULL, thread_black_fun, NULL);

pthread_join(id1, NULL);
pthread_join(id2, NULL);

参数记忆:

&tid            保存线程标识
NULL            使用默认线程属性
thread_fun      线程入口函数
arg             传给线程函数的参数

线程函数标准形式:

void *thread_fun(void *arg) {
    return NULL;
}

3. POSIX 无名信号量

头文件与类型:

#include <semaphore.h>

sem_t sem_id;

核心 API:

int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_wait(sem_t *sem);
int sem_post(sem_t *sem);
int sem_destroy(sem_t *sem);

互斥模板:

sem_t mutex;

sem_init(&mutex, 0, 1);

sem_wait(&mutex);
/* 临界区 */
sem_post(&mutex);

sem_destroy(&mutex);

sem_init() 参数:

&mutex    信号量地址
0         同一进程的线程之间共享
1         初值;表示开始时允许一个线程进入

对应理论操作:

sem_wait()    P 操作,申请资源
sem_post()    V 操作,释放资源

4. 两线程严格交替

先执行白线程,再执行黑线程:

sem_t white_turn;
sem_t black_turn;

sem_init(&white_turn, 0, 1);
sem_init(&black_turn, 0, 0);
// 白线程
sem_wait(&white_turn);
/* 白线程操作 */
sem_post(&black_turn);

// 黑线程
sem_wait(&black_turn);
/* 黑线程操作 */
sem_post(&white_turn);

记忆:

初值 1:开始即可执行
初值 0:必须等待其他线程唤醒

5. pthread 互斥锁

类型:

pthread_mutex_t mutex;

API:

pthread_mutex_init(&mutex, NULL);

pthread_mutex_lock(&mutex);
/* 临界区 */
pthread_mutex_unlock(&mutex);

pthread_mutex_destroy(&mutex);

完整填空顺序:

pthread_mutex_t
pthread_mutex_init
pthread_create
pthread_join
pthread_mutex_lock
pthread_mutex_unlock

6. POSIX 命名信号量

sem_t *s1 = sem_open("/s1", O_CREAT, 0666, 1);
sem_wait(s1);
sem_post(s1);
sem_close(s1);
sem_unlink("/s1");

注意参数形式:

sem_t sem;      sem_wait(&sem);   // 无名信号量变量
sem_t *s1;      sem_wait(s1);     // sem_open 返回的指针

第四章 进程信号

1. 常用头文件

#include <signal.h>     // signal、sigaction、kill、信号宏
#include <unistd.h>     // fork、pause、alarm、getppid
#include <sys/wait.h>   // wait
#include <stdlib.h>     // exit

2. 设置处理函数

旧接口:

signal(SIGALRM, ding);

推荐接口:

struct sigaction sa;

sa.sa_handler = ding;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;

sigaction(SIGALRM, &sa, NULL);

记忆:

signal / sigaction    设置处理方式
kill                  发送信号

处理函数:

void ding(int sig) {
    alarm_fired = 1;
}

3. 发送信号

int kill(pid_t pid, int sig);

典型填空:

kill(getppid(), SIGALRM);
kill(p1, 16);
kill(p2, 17);

参数:

pid    接收信号的进程
sig    要发送的信号

其他发送接口:

raise(SIGUSR1);        // 向当前进程发送信号
alarm(5);              // 5 秒后向自身发送 SIGALRM
sigqueue(pid, sig, value);

4. 等待信号

pause();

作用:

挂起当前进程,直到收到一个能够递送的信号。

标准父子信号模板:

if (fork() == 0) {
    sleep(5);
    kill(getppid(), SIGALRM);
    exit(0);
}

signal(SIGALRM, ding);
pause();
wait(NULL);

5. 高频信号

Ctrl-C       SIGINT
Ctrl-Z       SIGTSTP
alarm()      SIGALRM
kill PID     SIGTERM
kill -9 PID  SIGKILL

题库部分旧代码直接写信号编号 1617。考试填空可按题目填写;实际编程应优先使用 SIGUSR1SIGUSR2 等宏。


第五章 进程间通信

1. 匿名管道

头文件:

#include <unistd.h>

API:

int pipe(int pipefd[2]);

固定下标:

pipefd[0]    读端
pipefd[1]    写端

模板:

int fd[2];
pipe(fd);

write(fd[1], buf, strlen(buf));
read(fd[0], buf, sizeof(buf));

close(fd[0]);
close(fd[1]);

2. 有名管道 FIFO

头文件:

#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

API:

int mkfifo(const char *pathname, mode_t mode);

模板:

mkfifo("myfifo", 0666);

int fd = open("myfifo", O_WRONLY);
write(fd, buf, strlen(buf));
close(fd);

3. System V IPC 公共键值

头文件:

#include <sys/ipc.h>

生成键值:

key_t ftok(const char *pathname, int proj_id);

模板:

key_t key = ftok(".", 'a');

参数:

pathname    已存在的文件或目录路径
proj_id     项目标识,常用字符常量

4. System V 消息队列

头文件:

#include <sys/msg.h>
#include <sys/ipc.h>

消息结构:

struct msgbuf {
    long mtype;
    char mtext[100];
};

API:

int msgget(key_t key, int msgflg);

int msgsnd(
    int msqid,
    const void *msgp,
    size_t msgsz,
    int msgflg
);

ssize_t msgrcv(
    int msqid,
    void *msgp,
    size_t msgsz,
    long msgtyp,
    int msgflg
);

int msgctl(
    int msqid,
    int cmd,
    struct msqid_ds *buf
);

常用模板:

int msqid = msgget(key, IPC_CREAT | 0666);

msgsnd(
    msqid,
    &msg,
    sizeof(msg.mtext),
    0
);

msgrcv(
    msqid,
    &msg,
    sizeof(msg.mtext),
    1,
    0
);

msgctl(msqid, IPC_RMID, NULL);

重点:

msgsz 不包含 long mtype
msgtyp = 0      读取队列第一条消息
msgtyp > 0      读取指定类型消息
IPC_RMID        删除消息队列

5. System V 共享内存

头文件:

#include <sys/shm.h>
#include <sys/ipc.h>

API:

int shmget(key_t key, size_t size, int shmflg);

void *shmat(
    int shmid,
    const void *shmaddr,
    int shmflg
);

int shmdt(const void *shmaddr);

int shmctl(
    int shmid,
    int cmd,
    struct shmid_ds *buf
);

完整模板:

int shmid = shmget(
    key,
    1024,
    IPC_CREAT | 0666
);

char *addr = shmat(
    shmid,
    NULL,
    0
);

strcpy(addr, "hello");

shmdt(addr);

shmctl(
    shmid,
    IPC_RMID,
    NULL
);

参数记忆:

shmget:
key      IPC 键值
size     共享内存大小
shmflg   权限和创建标志

shmat:
shmid      共享内存标识符
shmaddr    映射地址,通常填 NULL
shmflg     0 表示可读写;SHM_RDONLY 表示只读

6. System V 信号量集

头文件:

#include <sys/sem.h>
#include <sys/ipc.h>

API:

int semget(key_t key, int nsems, int semflg);

int semop(
    int semid,
    struct sembuf *sops,
    size_t nsops
);

int semctl(
    int semid,
    int semnum,
    int cmd,
    ...
);

操作结构:

struct sembuf {
    unsigned short sem_num;
    short sem_op;
    short sem_flg;
};

P 操作:

struct sembuf p = {
    .sem_num = 0,
    .sem_op = -1,
    .sem_flg = 0
};

semop(semid, &p, 1);

V 操作:

struct sembuf v = {
    .sem_num = 0,
    .sem_op = 1,
    .sem_flg = 0
};

semop(semid, &v, 1);

固定含义:

sem_num    操作信号量集中的第几个信号量
sem_op=-1  P 操作
sem_op=1   V 操作
nsops=1    本次操作一个 sembuf

删除信号量集:

semctl(semid, 0, IPC_RMID);

第六章 设备驱动与内核模块

1. 内核模块头文件

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

2. 模块入口与出口

static int __init my_init(void) {
    printk(KERN_INFO "module loaded\n");
    return 0;
}

static void __exit my_exit(void) {
    printk(KERN_INFO "module removed\n");
}

module_init(my_init);
module_exit(my_exit);

固定填写:

__init
__exit
module_init
module_exit

3. 模块信息宏

MODULE_LICENSE("GPL");
MODULE_AUTHOR("name");
MODULE_DESCRIPTION("description");
MODULE_VERSION("1.0");

最常考:

MODULE_LICENSE("GPL");

4. 内核日志

printk(KERN_INFO "message\n");

常见日志级别:

KERN_EMERG
KERN_ALERT
KERN_CRIT
KERN_ERR
KERN_WARNING
KERN_NOTICE
KERN_INFO
KERN_DEBUG

查看日志:

dmesg

5. 模块命令

insmod module.ko       # 装载模块
rmmod module           # 卸载模块
lsmod                  # 查看模块
modinfo module.ko      # 查看模块信息
dmesg                   # 查看内核输出

6. 字符设备 file_operations

常见头文件:

#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>

常见回调:

static int dev_open(
    struct inode *inode,
    struct file *file
);

static int dev_release(
    struct inode *inode,
    struct file *file
);

static ssize_t dev_read(
    struct file *file,
    char __user *buf,
    size_t count,
    loff_t *ppos
);

static ssize_t dev_write(
    struct file *file,
    const char __user *buf,
    size_t count,
    loff_t *ppos
);

操作表:

static const struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = dev_open,
    .read = dev_read,
    .write = dev_write,
    .release = dev_release,
};

常见成员:

.owner
.open
.read
.write
.release
.unlocked_ioctl

7. 用户空间与内核空间复制

copy_to_user(user_buf, kernel_buf, count);
copy_from_user(kernel_buf, user_buf, count);

方向:

copy_to_user      内核 → 用户
copy_from_user    用户 → 内核

高频头文件总表

#include <stdio.h>       // printf、perror、fflush
#include <stdlib.h>      // exit、system、abort
#include <string.h>      // strcpy、strlen、memset
#include <errno.h>       // errno

#include <unistd.h>      // fork、exec、pipe、read、write、close
#include <sys/types.h>   // pid_t 等系统类型
#include <sys/wait.h>    // wait、waitpid
#include <sys/stat.h>    // 权限宏、mkfifo
#include <fcntl.h>       // open 及 O_* 标志

#include <pthread.h>     // pthread API
#include <semaphore.h>   // POSIX 信号量
#include <signal.h>      // signal、sigaction、kill

#include <sys/ipc.h>     // System V IPC 公共定义、ftok
#include <sys/msg.h>     // 消息队列
#include <sys/shm.h>     // 共享内存
#include <sys/sem.h>     // System V 信号量

高频 API 固定搭配

fork       → getpid / getppid / wait
fork       → exec → wait
open       → read / write → close
pipe       → read / write → close
pthread_create → pthread_join
sem_init   → sem_wait / sem_post → sem_destroy
pthread_mutex_init → lock / unlock → destroy
signal     → pause / kill
msgget     → msgsnd / msgrcv → msgctl
shmget     → shmat → shmdt → shmctl
semget     → semop → semctl
module_init → module_exit

最后速记

fork:父返回子 PID,子返回 0
pipefd[0] 读,pipefd[1] 写
sem_wait 是 P,sem_post 是 V
互斥初值 1,同步等待初值 0
signal 注册,kill 发送,pause 等待
msgsz 不包含 mtype
shmat 的 shmaddr 通常填 NULL
IPC_CREAT 创建,IPC_RMID 删除
copy_to_user:内核到用户
copy_from_user:用户到内核

阅读路径

文章目录