最近在学习Linux系统编程的章节,接触到了两种信号量,所以专门研究了二者的区别,将二者的对比记录于此。
在Linux多线程/进程开发中,信号量是解决同步问题的核心工具之一。System V和POSIX是两种主流的实现方式,它们的区别直接影响开发效率和性能。以下是两者的关键差异总结:
特性 | System V信号量 | POSIX信号量 |
---|---|---|
内核依赖 | 由内核维护,生命周期与进程无关 | 分为两种: • 有名信号量(内核维护,文件关联) • 无名信号量(进程内存维护) |
持久性 | 显式删除前永久存在(需semctl(IPC_RMID) ) |
无名信号量随进程消亡;有名信号量需手动删除 |
操作类型 | System V函数 | POSIX函数 |
---|---|---|
初始化 | semget() + semctl(SETVAL) 两步操作 |
无名:sem_init() 有名: sem_open() |
PV操作 | semop() (支持原子批量操作) |
sem_wait() (阻塞)sem_post() (释放) |
错误处理 | 通过全局变量errno 判断 |
函数直接返回错误码(如EAGAIN ) |
场景 | 推荐方案 | 原因 |
---|---|---|
跨进程复杂同步 | System V信号量集(支持多信号量原子操作) | 可同时操作多个信号量,避免死锁 |
线程间轻量级同步 | POSIX无名信号量(sem_init ) |
基于内存,无内核开销,性能更高 |
简单进程间同步 | POSIX有名信号量(sem_open ) |
API更简洁,兼容现代编程规范 |
特性 | System V | POSIX |
---|---|---|
信号量集合 | ️ 支持多信号量集合(如semget( ,5) ) |
仅支持单个信号量操作 |
超时机制 | 需自定义实现 | ️ sem_timedwait() 支持超时等待 |
信号量值范围 | 无明确限制(内核参数约束) | 无名信号量通常限制为32位整数 |
优先POSIX的场景:
std::counting_semaphore
)坚持System V的场景:
附:典型代码片段
System V信号量集初始化
key_t key = ftok("/tmp", 'S');
int semid = semget(key, 3, 0666 | IPC_CREAT); // 创建3个信号量
union semun arg;
arg.array = (unsigned short[]){1, 1, 1};
semctl(semid, 0, SETALL, arg); // 全部初始化为1
POSIX有名信号量
sem_t *sem = sem_open("/mysem", O_CREAT, 0666, 1);
sem_wait(sem); // P操作
// 临界区操作
sem_post(sem); // V操作
sem_close(sem);
sem_unlink("/mysem"); // 删除内核对象
总结:POSIX信号量是现代开发的首选,但System V在复杂进程同步中仍有不可替代性。选择时需权衡性能、功能需求及系统兼容性。