CSAPP 第八章:Exception 异常控制流
程序并不是严格按照 一条指令接一条指令 顺序执行,硬件和操作系统提供机制打断并切换执行流。
异常控制流 (ECF) :CPU 在某些事件发生时中断当前指令流,转向处理事件,再返回或终止。
📌 层次结构 :
硬件级:异常 (Exception)、中断 (Interrupt)
操作系统级:进程调度 (Context Switch)
用户级:信号 (Signals)、非本地跳转 (setjmp / longjmp)
异常
异常 :由硬件或软件事件触发的控制流跳转,CPU 转到内核中的异常处理程序。
通过 异常向量表 (Exception Table) 查找对应的处理程序。
异常类型
类型
特点
示例
中断
异步事件,来自外部设备
时钟中断、键盘输入
陷阱
同步事件,用户程序有意触发
系统调用 (syscall)
故障
可恢复错误,修复后重新执行
缺页异常 (Page Fault)
终止
致命错误,不可恢复
硬件故障、内存错误
📌 区别 :
陷阱/系统调用 :返回到下一条指令。
故障 :若修复成功,重新执行当前指令。
终止 :程序直接中止。
系统调用
系统调用 是用户程序和操作系统内核之间的接口。
用户程序无法直接访问硬件资源(如磁盘、网络、终端),必须通过系统调用请求内核服务。
本质:通过 陷阱 (trap) 指令 从用户模式切换到内核模式,再切回用户模式。
用户模式与内核模式
用户模式 (User Mode)
普通程序运行的模式,受到严格限制。
无法直接执行特权指令(如 I/O、修改页表)。
只能访问自己进程的虚拟地址空间。
内核模式 (Kernel Mode)
操作系统运行的模式,权限最高。
可以执行所有指令,访问所有物理资源。
内核代码和数据必须在内核模式下执行。
系统调用的执行流程
用户进程调用库函数(如 printf
→ 内部调用 write
系统调用)。
库函数执行 syscall
指令,触发 陷阱 (trap) ,CPU 切换到内核模式。
CPU 根据系统调用号,从 系统调用表 找到对应的内核处理函数。
内核执行相应操作(如向终端写数据)。
内核返回,CPU 切回用户模式,继续执行用户进程的下一条指令。
示例 1 2 3 4 5 #include <unistd.h> int main () { write(1 , "hello\n" , 6 ); return 0 ; }
进程控制 上下文切换 保存当前进程的 CPU 状态,恢复另一个进程的 CPU 状态。
上下文切换 :操作系统内核在多个进程/线程之间切换 CPU 的执行权。
上下文 :进程运行所需的全部状态,包括:
程序计数器 (PC):下一条要执行的指令地址
通用寄存器内容
栈指针 (SP) 和帧指针 (FP)
程序状态字 (PSW) → 包含条件码、模式位(用户/内核态)
虚拟内存相关的页表基地址
内核栈和内核寄存器
信号
信号是 软件中断 ,由内核发送,用来通知进程某些事件发生。
信号机制允许内核和用户进程之间,以及进程和进程之间进行简单的异步通信。
常见信号表
信号
数值 (x86/Linux)
默认行为
说明
SIGHUP
1
终止
挂起/终止进程,常在终端关闭时发送
SIGINT
2
终止
由 Ctrl+C 触发
SIGQUIT
3
终止+core dump
由 Ctrl+\ 触发
SIGILL
4
终止+core dump
非法指令
SIGABRT
6
终止+core dump
调用 abort()
产生
SIGFPE
8
终止+core dump
算术错误 (如除零)
SIGKILL
9
终止
强制杀死进程,不能捕获/忽略
SIGSEGV
11
终止+core dump
段错误,非法内存访问
SIGPIPE
13
终止
向无读端的管道写入
SIGALRM
14
终止
定时器 (由 alarm()
设置) 到时
SIGTERM
15
终止
默认的“优雅”终止信号
SIGCHLD
17
忽略
子进程退出/暂停时发给父进程
SIGCONT
18
继续
使停止的进程继续运行
SIGSTOP
19
停止
强制停止进程,不能捕获/忽略
SIGTSTP
20
停止
由 Ctrl+Z 触发
SIGUSR1
10
终止
用户自定义信号1
SIGUSR2
12
终止
用户自定义信号2
默认行为
终止 (Terminate):进程直接退出,返回码由信号决定
忽略 (Ignore):进程不做任何响应,继续执行
停止 (Stop):进程挂起,直到收到 SIGCONT
继续 (Continue):恢复被 SIGSTOP 或 SIGTSTP 停止的进程
终止+core dump:进程退出并生成 core 文件,供调试用
信号处理方式
默认处理:采用系统定义的行为 (如终止/忽略)
自定义信号处理函数:通过 signal()
或 sigaction()
注册 handler
忽略信号:将处理设为 SIG_IGN
不可捕获/不可忽略的信号:如 SIGKILL
和 SIGSTOP
信号传递机制
内核检测到事件 (如键盘输入、异常) → 产生信号
内核将信号标记到进程控制块 (PCB)
当进程从内核态返回用户态时,内核检查是否有待处理的信号
如果有:
自定义 handler → 跳转执行 handler,执行后恢复原程序
默认处理 → 终止 / 停止 / 忽略
等待集与阻塞集
等待集 (pending set) :已经到达但还没处理的信号。
阻塞集 (blocked set) :被进程临时屏蔽的信号,阻塞期间不会被处理,只会放进等待集。
当信号解除阻塞时,内核会立即处理等待集里的信号。
示例 示例1:SIGINT (Ctrl+C) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <stdio.h> #include <signal.h> #include <unistd.h> void handler (int sig) { printf ("Caught SIGINT (%d), but not exiting!\n" , sig); }int main () { signal(SIGINT, handler); while (1 ) { printf ("Running...\n" ); sleep(1 ); } return 0 ; }
运行结果:
默认情况:Ctrl+C 会终止程序
注册 handler 后:Ctrl+C 触发 handler
,打印提示,但进程不会退出
示例2:SIGCHLD (子进程退出) 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 <stdio.h> #include <signal.h> #include <sys/wait.h> #include <unistd.h> void handler (int sig) { int status; pid_t pid = wait(&status); printf ("Child %d terminated\n" , pid); }int main () { signal(SIGCHLD, handler); if (fork() == 0 ) { printf ("Child running...\n" ); sleep(2 ); _exit(0 ); } while (1 ) { printf ("Parent running...\n" ); sleep(1 ); } return 0 ; }
运行结果:
父进程持续运行,输出 “Parent running…”
子进程结束后,内核发送 SIGCHLD
给父进程
父进程 handler 捕获信号并调用 wait()
,避免子进程变为僵尸
示例3:信号不排队 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 28 29 30 31 32 33 34 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <sys/wait.h> void sigchld_handler (int sig) { printf ("Parent got SIGCHLD\n" ); int status; pid_t pid = wait(&status); if (pid > 0 ) { printf ("Reaped child %d\n" , pid); } }int main () { signal(SIGCHLD, sigchld_handler); for (int i = 0 ; i < 2 ; i++) { if (fork() == 0 ) { printf ("Child %d (PID=%d) exits\n" , i, getpid()); exit (0 ); } } while (1 ) { pause(); } return 0 ; }
示例4:阻塞集和等待集 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 28 29 30 31 32 #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> void handler (int sig) { printf ("Handled signal %d\n" , sig); }int main () { sigset_t mask, oldmask; signal(SIGINT, handler); sigemptyset(&mask); sigaddset(&mask, SIGINT); sigprocmask(SIG_BLOCK, &mask, &oldmask); printf ("SIGINT is blocked. Try pressing Ctrl+C now (no immediate effect).\n" ); sleep(5 ); printf ("Now unblocking SIGINT...\n" ); sigprocmask(SIG_SETMASK, &oldmask, NULL ); sleep(2 ); return 0 ; }
执行结果示例 1 2 3 4 SIGINT is blocked. Try pressing Ctrl+C now (no immediate effect). ^C Now unblocking SIGINT... Handled signal 2
解释:
在阻塞期间按下 Ctrl+C
,SIGINT
被放进 等待集 ,没有立刻触发 handler。
一旦解除阻塞,等待集里的 SIGINT
立刻被处理,执行 handler。
非本地跳转 (Nonlocal Jumps)
setjmp
/ longjmp
:允许程序从深层调用栈直接跳回之前保存的执行点。
常用于 错误处理 / 异常恢复 ,比如当深层函数遇到错误时,直接返回到主流程或错误处理代码,而不必一层层返回。
原理
setjmp(jmp_buf env)
:保存当前执行点的寄存器上下文,包括:
栈指针 (stack pointer)
程序计数器 (instruction pointer)
通用寄存器
longjmp(jmp_buf env, int val)
:恢复保存的上下文,从 setjmp
返回,返回值为 val
。
注意:
setjmp
第一次返回时返回 0
longjmp
恢复时,setjmp
返回 val
(通常非 0)
示例
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 28 29 30 31 32 33 34 35 #include <stdio.h> #include <setjmp.h> jmp_buf buf;void third () { printf ("third() encountered an error, jumping back\n" ); longjmp(buf, 1 ); }void second () { printf ("second() called\n" ); third(); printf ("This line will never be executed\n" ); }void first () { printf ("first() called\n" ); second(); printf ("This line will never be executed\n" ); }int main () { if (setjmp(buf) == 0 ) { printf ("setjmp returns 0, starting normal flow\n" ); first(); } else { printf ("back in main after longjmp, handling error\n" ); } printf ("Program continues normally\n" ); return 0 ; }
输出:
1 2 3 4 5 6 setjmp returns 0 , starting normal flowfirst () calledsecond () calledthird () encountered an error, jumping back back in main after longjmp, handling error Program continues normally
执行逻辑:
setjmp(buf)
保存当前上下文,第一次返回 0 → 执行 first()
→ second()
→ third()
third()
调用 longjmp(buf, 1)
,跳回 setjmp
所在位置
此时 setjmp
返回 1 → 进入 else
分支 → 执行错误处理
程序继续正常执行,而无需逐层返回
附录:系统调用复习 文件操作 open close 打开、关闭文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <fcntl.h> #include <unistd.h> int open (const char *pathname, int flags) ;int fd = open("example.txt" , O_RDONLY);int close (int fd) ;
read write 读写文件
1 2 3 #include <unistd.h> ssize_t read (int fd, void *buf, size_t count) ;ssize_t write (int fd, const void *buf, size_t count) ;
lseek 移动文件内指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 标准C库的函数#include <stdio.h> int fseek (FILE *stream, long offset, int whence) ; Linux系统函数#include <sys/types.h> #include <unistd.h> off_t lseek (int fd, off_t offset, int whence) ;
stat 获取文件的元数据
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 28 #include <sys/stat.h> #include <unistd.h> int stat (const char *pathname, struct stat *statbuf) ;int lstat (const char *pathname, struct stat *statbuf) ;struct stat { dev_t st_dev; ino_t st_ino; mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; dev_t st_rdev; off_t st_size; time_t st_atime; time_t st_mtime; time_t st_ctime; blksize_t st_blksize; blkcnt_t st_blocks; };
st_mode
中的文件类型可以通过以下宏检查:
文件类型:
S_ISREG(st_mode)
:常规文件。
S_ISDIR(st_mode)
:目录。
S_ISLNK(st_mode)
:符号链接。
S_ISCHR(st_mode)
:字符设备。
S_ISBLK(st_mode)
:块设备。
S_ISFIFO(st_mode)
:FIFO/管道。
S_ISSOCK(st_mode)
:套接字。
文件权限:
st_mode & S_IRUSR
:用户可读。
st_mode & S_IWUSR
:用户可写。
st_mode & S_IXUSR
:用户可执行。
文件属性操作函数 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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 int access (const char *pathname, int mode) ;int chmod (const char *filename, int mode) ;int chown (const char *path, uid_t owner, gid_t group) ;int truncate (const char *path, off_t length) ;
目录操作函数 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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 int rename (const char *oldpath, const char *newpath) ;int chdir (const char *path) ;char *getcwd (char *buf, size_t size) ;int mkdir (const char *pathname, mode_t mode) ;int rmdir (const char *pathname) ;
目录遍历函数 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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 DIR *opendir (const char *name) ;struct dirent *readdir (DIR *dirp) ;int closedir (DIR *dirp) ;struct dirent { ino_t d_ino; off_t d_off; unsigned short int d_reclen; unsigned char d_type; char d_name[256 ]; };
dup dup2 1 2 3 4 int dup (int oldfd) ;int dup2 (int oldfd, int newfd) ;
Linux多进程 管道 mkfifo
是一个用于创建命名管道(FIFO,First In First Out)的系统调用。命名管道用于在不同进程之间进行通信。
1 2 3 4 int mkfifo (const char *pathname, mode_t mode) ;
内存映射 这两个函数用于在文件映射/匿名映射 区开辟内存
重要:见内存映射注意事项.txt
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 28 29 30 31 32 33 34 35 36 37 38 39 #include <sys/mman.h> void *mmap (void *addr, size_t length, int prot, int flags, int fd, off_t offset) ;int munmap (void *addr, size_t length) ;
信号 通用信号发送函数 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 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <signal.h> int kill (pid_t pid, int sig) ;int raise (int sig) ;void abort (void ) ;
定时器 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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include <unistd.h> unsigned int alarm (unsigned int seconds) ;int setitimer (int which, const struct itimerval *new_val, struct itimerval *old_value) ;
信号捕捉 注意:SIGKILL SIGSTOP不能被捕捉,不能被忽略
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 28 29 30 31 sighandler_t signal (int signum, sighandler_t handler) ;int sigaction (int signum, const struct sigaction *act, struct sigaction *oldact) ;
信号集 这些函数用于操作和管理信号集(sigset_t),常用于信号处理的信号屏蔽和管理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 int sigemptyset (sigset_t *set ) ;int sigfillset (sigset_t *set ) ;int sigaddset (sigset_t *set , int signum) ;int sigdelset (sigset_t *set , int signum) ;int sigismember (const sigset_t *set , int signum) ;int sigprocmask (int how, const sigset_t *set , sigset_t *oldset) ;int sigpending (sigset_t *set ) ;
SIGCHLD 信号产生条件 SIGCHLD信号产生的3个条件: 1.子进程结束 2.子进程暂停了 3.子进程继续运行 都会给父进程发送该信号,父进程默认忽略该信号。
共享内存 头文件 #include <sys/ipc.h>
此头文件定义了与 System V IPC(进程间通信) 相关的常量和数据结构。主要功能包括:
定义键值类型和标志 :
key_t
:共享内存、消息队列或信号量的键值类型。
IPC_CREAT
:如果指定键的 IPC 对象不存在,则创建一个新的对象。
IPC_EXCL
:与 IPC_CREAT
一起使用,确保指定键的 IPC 对象不存在,否则操作失败。
IPC_PRIVATE
:创建一个仅供调用进程使用的新 IPC 对象。
通用命令(用于控制 IPC 对象) :
IPC_RMID
:删除 IPC 对象。
IPC_SET
:设置 IPC 对象的权限。
IPC_STAT
:获取 IPC 对象的状态信息。
#include <sys/shm.h>
此头文件定义了与 System V 共享内存 相关的常量、数据结构和函数。主要内容包括:
共享内存标识符和标志 :
shmget()
:创建或访问一个共享内存段。
shmat()
:将共享内存附加到调用进程的地址空间。
shmdt()
:将共享内存从调用进程的地址空间分离。
shmctl()
:控制共享内存段(例如删除或查询状态)。
常量定义 :
SHM_RDONLY
:共享内存以只读方式附加。
SHM_R
和 SHM_W
:读取和写入共享内存的权限。
数据结构 :
struct shmid_ds
:存储共享内存段的元数据,例如大小、权限和使用情况。
实际实现 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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 #include <sys/ipc.h> #include <sys/shm.h> int shmget (key_t key, size_t size, int shmflg) ;int shmid = shmget(key, 1024 , 0666 | IPC_CREAT | IPC_EXCL);void *shmat (int shmid, const void *shmaddr, int shmflg) ;int shmdt (const void *shmaddr) ;int shmctl (int shmid, int cmd, struct shmid_ds *buf) ;struct shmid_ds { struct ipc_perm shm_perm ; size_t shm_segsz; time_t shm_atime; time_t shm_dtime; time_t shm_ctime; pid_t shm_cpid; pid_t shm_lpid; shmatt_t shm_nattch; };struct ipc_perm { uid_t uid; gid_t gid; mode_t mode; };key_t ftok (const char *pathname, int proj_id) ;
共享内存操作命令
1 2 3 4 5 # 查看进程间通信资源信息 ipcs -a # 打印当前系统中所有的进程间通信方式的信息 ipcs -m # 打印使用共享内存进行进程间通信的信息 ipcs -q # 打印使用消息队列进行进程间通信的信息 ipcs -s # 打印使用信号进行进程间通信的信息
1 2 3 4 5 6 7 # 删除进程间通信资源 ipcrm -M shmkey # 移除用 shmkey 创建的共享内存段 ipcrm -m shmid # 移除用 shmid 标识的共享内存段 ipcrm -Q msgkey # 移除用 msgkey 创建的消息队列 ipcrm -q msqid # 移除用 msqid 标识的消息队列 ipcrm -S semkey # 移除用 semkey 创建的信号 ipcrm -s semid # 移除用 semid 标识的信号
操作系统如何知道一块共享内存被多少个进程关联?
操作系统通过 struct shmid_ds
结构体中的 shm_nattch
成员来记录关联的进程数量。
可以对共享内存进行多次删除吗?
可以。shmctl
标记共享内存为删除状态,但不会立即删除。只有当与共享内存关联的进程数为 0 时,内核才会实际删除它。
共享内存与内存映射的区别
特性
共享内存
内存映射
创建方式
直接创建共享内存
需要磁盘文件(除非是匿名映射)
效率
更高
较低
内存访问
所有进程访问同一块共享内存
每个进程在自己的虚拟地址空间中有独立的内存
数据安全
进程退出共享内存仍存在
进程退出,内存映射区数据消失
系统宕机时,数据丢失
系统宕机时,内存映射区数据仍保存在磁盘文件中
生命周期
进程退出共享内存依然存在
进程退出,内存映射区销毁
进程退出自动取消关联,关机时可销毁
通过标记删除或关机删除内存映射区
Linux多线程 线程管理 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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 int pthread_create (pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) ;pthread_t pthread_self (void ) ;int pthread_equal (pthread_t t1, pthread_t t2) ;void pthread_exit (void *retval) ;int pthread_join (pthread_t thread, void **retval) ;int pthread_detach (pthread_t thread) ;int pthread_cancel (pthread_t thread) ;
线程属性 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 28 29 30 31 32 33 34 35 36 37 38 39 40 pthread_attr_t typedef struct pthread_attr { int detachstate; size_t stacksize; void *stackaddr; int schedpolicy; int schedparam; int inheritsched; int guardsize; } pthread_attr_t ;int pthread_attr_init (pthread_attr_t *attr) ;int pthread_attr_destroy (pthread_attr_t *attr) ;int pthread_attr_getdetachstate (const pthread_attr_t *attr, int *detachstate) ;int pthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate) ;
互斥量 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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 pthread_mutex_t mutex;int pthread_mutex_init (pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr) ;int pthread_mutex_destroy (pthread_mutex_t *mutex) ;int pthread_mutex_lock (pthread_mutex_t *mutex) ;int pthread_mutex_trylock (pthread_mutex_t *mutex) ;int pthread_mutex_unlock (pthread_mutex_t *mutex) ;
读写锁 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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 #include <stdio.h> #include <pthread.h> #include <unistd.h> pthread_rwlock_t rwlock;int pthread_rwlock_init (pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr) ;int pthread_rwlock_destroy (pthread_rwlock_t *rwlock) ;int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) ;int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) ;int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) ;int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) ;int pthread_rwlock_unlock (pthread_rwlock_t *rwlock) ;
条件变量 条件变量的条件指的是被cond
所阻塞的线程需要等待的一个相应通知,而不是某个逻辑表达式
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 pthread_cond_t cond;int pthread_cond_init (pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr) ;int pthread_cond_destroy (pthread_cond_t *cond) ;int pthread_cond_wait (pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex) ;int pthread_cond_timedwait (pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime) ;struct timespec { time_t tv_sec; long tv_nsec; };int pthread_cond_signal (pthread_cond_t *cond) ;int pthread_cond_broadcast (pthread_cond_t *cond) ;
信号量 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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 sem_t sem;int sem_init (sem_t *sem, int pshared, unsigned int value) ;int sem_destroy (sem_t *sem) ;int sem_wait (sem_t *sem) ;int sem_trywait (sem_t *sem) ;int sem_timedwait (sem_t *sem, const struct timespec *abs_timeout) ;int sem_post (sem_t *sem) ;