semget – 获取信号量集标识符
函数介绍
semget
系统调用用于创建或访问一个System V信号量集。信号量是一种用于进程间同步的机制,主要用于控制对共享资源的访问,防止多个进程同时访问同一资源造成冲突。
函数原型
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
功能
参数
key_t key
: 信号量集的键值IPC_PRIVATE
: 创建私有信号量集- 正整数: 通过
ftok()
函数生成的键值
int nsems
: 信号量集中信号量的个数(创建时使用)int semflg
: 标志位组合IPC_CREAT
: 如果信号量集不存在则创建IPC_EXCL
: 与IPC_CREAT配合使用,如果已存在则失败- 权限位: 如0666(读写权限)
返回值
- 成功时返回信号量集的标识符(非负整数)
- 失败时返回-1,并设置errno:
EACCES
: 权限不足EEXIST
: 信号量集已存在(使用IPC_EXCL时)EINVAL
: 参数无效ENOENT
: 信号量集不存在且未指定IPC_CREAT
相似函数
semctl()
: 控制信号量集semop()
: 操作信号量集ftok()
: 生成System V IPC键值
示例代码
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <string.h>
// 信号量操作联合体(某些系统需要)
union semun {
int val; // 用于SETVAL
struct semid_ds *buf; // 用于IPC_STAT和IPC_SET
unsigned short *array; // 用于GETALL和SETALL
};
int main() {
key_t key;
int semid;
printf("=== Semget函数示例 ===\n");
// 示例1: 使用IPC_PRIVATE创建私有信号量集
printf("\n示例1: 创建私有信号量集\n");
semid = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
if (semid == -1) {
perror("semget IPC_PRIVATE失败");
exit(EXIT_FAILURE);
}
printf(" 成功创建私有信号量集,标识符: %d\n", semid);
// 删除信号量集
if (semctl(semid, 0, IPC_RMID) == -1) {
perror("删除信号量集失败");
} else {
printf(" 成功删除信号量集\n");
}
// 示例2: 使用ftok生成键值创建信号量集
printf("\n示例2: 使用ftok创建信号量集\n");
// 生成键值(基于当前文件和项目ID)
key = ftok(".", 'a');
if (key == -1) {
perror("ftok失败");
exit(EXIT_FAILURE);
}
printf(" 生成的键值: %d\n", key);
// 创建信号量集(包含3个信号量)
semid = semget(key, 3, 0666 | IPC_CREAT);
if (semid == -1) {
perror("semget创建失败");
exit(EXIT_FAILURE);
}
printf(" 成功创建信号量集,标识符: %d\n", semid);
// 示例3: 尝试创建已存在的信号量集
printf("\n示例3: 尝试重复创建信号量集\n");
int semid2 = semget(key, 3, 0666 | IPC_CREAT | IPC_EXCL);
if (semid2 == -1) {
if (errno == EEXIST) {
printf(" 信号量集已存在\n");
} else {
perror(" semget失败");
}
} else {
printf(" 意外创建了新的信号量集: %d\n", semid2);
}
// 示例4: 获取已存在的信号量集
printf("\n示例4: 获取已存在的信号量集\n");
int semid3 = semget(key, 0, 0666);
if (semid3 == -1) {
perror("获取信号量集失败");
} else {
printf(" 成功获取信号量集,标识符: %d\n", semid3);
// 验证是否为同一个信号量集
if (semid3 == semid) {
printf(" 确认为同一个信号量集\n");
}
}
// 示例5: 错误处理演示
printf("\n示例5: 错误处理\n");
// 尝试访问不存在的信号量集(不创建)
int semid4 = semget(12345, 1, 0666);
if (semid4 == -1) {
if (errno == ENOENT) {
printf(" 信号量集不存在: %s\n", strerror(errno));
} else {
perror(" 其他错误");
}
}
// 清理:删除创建的信号量集
printf("\n清理资源...\n");
if (semctl(semid, 0, IPC_RMID) == -1) {
perror("清理信号量集失败");
} else {
printf(" 成功清理信号量集\n");
}
return 0;
}