semget系统调用及示例

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;
}
此条目发表在linux文章分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注