深入了解 sem init 和 semget:Linux 进程间通信208
semget
semget() 系统调用用于创建或获取一个已存在的信号量集。信号量集是一种用于进程间通信的特殊数据结构,它包含一个或多个信号量。信号量是一个共享的整数,用于协调对共享资源的访问。
semget() 函数的原型如下:```c
#include
#include
#include
int semget(key_t key, int nsems, int semflg);
```
其中:* `key` 是一个整数,用于唯一标识信号量集。可以通过 ftok() 函数生成 key。
* `nsems` 指定信号量集中的信号量数量。
* `semflg` 指定创建或获取信号量集的标志,可以使用以下标志:
* `IPC_CREAT`:如果信号量集不存在,则创建它。
* `IPC_EXCL`:只有在信号量集不存在时才创建它。如果信号量集已存在,则 semget() 将失败。
* `0666`:指定信号量集的访问权限。
semget() 函数返回信号量集的标识符(ID),如果发生错误,则返回 -1。
semctl()
semctl() 系统调用用于控制信号量集。它可以执行各种操作,例如获取信号量集的属性、设置信号量的值或删除信号量集。
semctl() 函数的原型如下:```c
#include
#include
#include
int semctl(int semid, int semnum, int cmd, ...);
```
其中:* `semid` 是信号量集的标识符。
* `semnum` 指定要操作的信号量的编号。
* `cmd` 指定要执行的操作,可以使用以下命令:
* `GETVAL`:获取信号量的值。
* `SETVAL`:设置信号量的值。
* `GETALL`:获取信号量集的所有信号量的值。
* `SETALL`:设置信号量集的所有信号量的值。
* `IPC_RMID`:删除信号量集。
* `...` 是可选的参数,具体取决于要执行的操作。
semctl() 函数返回 0 表示成功,如果发生错误,则返回 -1。
semop()
semop() 系统调用用于原子操作多个信号量。它可以执行各种操作,例如增加或减少信号量值或对信号量进行等待或信号操作。
semop() 函数的原型如下:```c
#include
#include
#include
int semop(int semid, struct sembuf *sops, size_t nsops);
```
其中:* `semid` 是信号量集的标识符。
* `sops` 是一个指向 sembuf 结构的数组,其中包含要执行的操作。
* `nsops` 指定 `sops` 数组中的元素数量。
sembuf 结构的定义如下:```c
struct sembuf {
short sem_num; // 要操作的信号量的编号
short sem_op; // 要执行的操作
short sem_flg; // 操作标志
};
```
sem_op 字段可以指定以下操作:* `-1`:对信号量进行等待操作。
* `1`:对信号量进行信号操作。
* `0`:只是检查信号量。
sem_flg 字段可以指定以下标志:* `SEM_UNDO`:在进程退出时自动撤消 semop() 操作。
* `IPC_NOWAIT`:如果信号量不可用,则立即返回,不阻塞。
semop() 函数返回 0 表示成功,如果发生错误,则返回 -1。
示例代码
以下示例代码演示了如何使用 semget()、semctl() 和 semop() 创建、获取和使用一个信号量集:```c
#include
#include
#include
#include
int main() {
// 创建一个信号量集,包含 2 个信号量
int semid = semget(IPC_PRIVATE, 2, 0666 | IPC_CREAT);
if (semid == -1) {
perror("semget");
return 1;
}
// 获取第一个信号量的值
int val = semctl(semid, 0, GETVAL);
if (val == -1) {
perror("semctl");
return 1;
}
// 打印第一个信号量的值
printf("First semaphore value: %d", val);
// 对第二个信号量进行信号操作
struct sembuf sops[1];
sops[0].sem_num = 1;
sops[0].sem_op = 1;
sops[0].sem_flg = 0;
if (semop(semid, sops, 1) == -1) {
perror("semop");
return 1;
}
// 对第一个信号量进行等待操作
sops[0].sem_num = 0;
sops[0].sem_op = -1;
sops[0].sem_flg = 0;
if (semop(semid, sops, 1) == -1) {
perror("semop");
return 1;
}
// 删除信号量集
if (semctl(semid, 0, IPC_RMID) == -1) {
perror("semctl");
return 1;
}
return 0;
}
```
2024-10-18