semget系统调用及示例

semget - 获取信号量集标识符

函数介绍

semget系统调用用于创建或访问一个System V信号量集。信号量是一种用于进程间同步的机制,主要用于控制对共享资源的访问,防止多个进程同时访问同一资源造成冲突。

函数原型

1
2
3
4
5
6
#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: 信号量集中信号量的个数(创建时使用)

data-ad-format="fluid" data-ad-layout-key="-7k+ex-4a-9w+4a">

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键值

示例代码

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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#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;
}
data-ad-format="auto" data-full-width-responsive="true">