信号量使用流程
信号量使用流程(POSIX 信号量)
1️⃣ 信号量创建与初始化
A. 命名信号量(sem_open
)
#include <semaphore.h>sem_t *sem;
sem_unlink("/SemChkCrt"); // 删除可能存在的同名信号量
sem = sem_open("/SemChkCrt", O_CREAT, 0666, 1); // 创建信号量,初值为1
if (sem == SEM_FAILED) {perror("sem_open failed");
}
- sem_unlink 删除系统中已有同名信号量,保证干净初值
- O_CREAT 表示创建信号量,如果已存在会返回现有信号量
- 0666 权限可读可写
- 最后一个参数 1 是信号量初值(可用资源数量)
- 返回值:sem_t*,失败返回 SEM_FAILED
B. 非命名信号量(sem_init
)
sem_t sem;
sem_init(&sem, 0, 1); // 0 表示线程间共享,1 是初值
2️⃣ 信号量使用
A. 等待资源(P 操作)
sem_wait(sem); // 阻塞直到信号量 > 0
B. 尝试获取资源(非阻塞)
if (sem_trywait(sem) == 0) {// 成功获取
} else {// 没有资源
}
C. 释放资源(V 操作)
sem_post(sem); // 信号量 +1,可能唤醒等待线程
D. 获取当前值(调试用)
int val;
sem_getvalue(sem, &val); // 获取当前信号量计数
3️⃣ 项目应用示例(y[0] + GetSemOpen)
// 创建信号量并存入数组
y[0] = (UintPtr)GetSemOpen(x, O_CREAT, 0666, 1);// 检查是否创建成功
f = PtrEqlErrChk(y[0], (UintPtr)SEM_FAILED, "错误原因", z);// 使用信号量
sem_wait((sem_t*)y[0]); // P 操作
sem_post((sem_t*)y[0]); // V 操作// 调试查看信号量值
set $ptr = (int*) malloc(sizeof(int))
call sem_getvalue((sem_t*)y[0], $ptr)
p *$ptr
call free($ptr)
4️⃣ 信号量释放和清理
A. 命名信号量
sem_close((sem_t*)y[0]); // 关闭信号量句柄
sem_unlink("/SemChkCrt"); // 删除系统中的信号量名字
B. 非命名信号量
sem_destroy(&sem);
5️⃣ 使用注意事项
- 命名信号量可能已存在 → 用 sem_unlink 删除
- UintPtr 存的是指针整数 → 操作前需要强转回 (sem_t*)
- 调试查看值用 sem_getvalue 或 gdb 强转打印
- 指针算术自动按元素大小计算,不要手动乘 sizeof
bug:
现象
在多次运行测试代码的时候,会发先原本运行通过的测试代码,出现了阻塞,不往下继续运行。
通过gdb调试发现是程序是跑到sem_wait这一行不动的,随机打印
信号量为y[0]=0,并且调用sem_post信号量增加,
然后再去查看SemOpen 返回的是 sem_t*返回的值,发现信号量一创建计数值就显示为0了。这就存在两种可能
a = sem_open(w,x,y,z);
-
z = 1 传进去作为“资源数量”,理论上应该初始化信号量值为 1 如果 sem_getvalue 打印出来是 0,说明
GetSemOpen 内部 没有把信号量值初始化为 c,或者初始化在 不同进程/线程 -
另一种可能:你使用的是命名信号量(sem_open),而系统里之前有同名信号量,O_CREAT
会返回现有信号量,而这个信号量的值可能已经被其他线程/进程消耗掉了。
由于这是一个系统函数所以,第二种情况可能性会大一点,
删除这个信号量,并且在测试代码末尾加上sem_unlink操作,问题解决。