进程间通信方式(四):System V 信号量

一、概念

二、特点

三、信号量数据结构

        信号量具有自身特有的数据结构 semid_ds,该结构说明了信号量的一些状态信息等等,详细信息可参阅文件 /usr/include/linux/sem.h

struct semid_ds {    
    struct ipc_perm sem_perm;       /* permissions .. see ipc.h */    
    __kernel_time_t sem_otime;      /* last semop time */    
    __kernel_time_t sem_ctime;      /* last change time */    
    struct sem  *sem_base;      	/* ptr to first semaphore in array */    
    struct sem_queue *sem_pending;      	/* pending operations to be processed */    
    struct sem_queue **sem_pending_last;    /* last pending operation */    
    struct sem_undo *undo;          /* undo requests on this array */    
    unsigned short  sem_nsems;      /* no. of semaphores in array */    
};

四、信号量相关函数

1. semget

  • 【头文件】:#include #include #include
  • 【函数原型】:int semget(key_t key, int nsems, int semflg);
  • 【功能】:创建或访问一个信号量集
  • 【参数】:

        (1)key:信号量集的键值,由 ftok() 生成
        (2)nsems:信号量集中信号量的个数
        (3)semflg:权限标志位,由两部分组成,一部分为IPC对象存取权限(含义同 ipc_perm 中的 mode),另一部分为IPC对象创建模式标志(IPC_CREAT、IPC_EXCL),一般会将这两部分进行 | 运算,从而完成对IPC对象创建的管理

  • 【返回值】:成功返回一个信号量集标识符(非负整数);失败则返回 -1,并将 errno 设置为错误标识符

进程间通信方式(四):System V 信号量_第1张图片

创建或打开一个 IPC 对象的逻辑流程图

【示例】:演示 IPC_CREAT|IPC_EXCL 的使用效果
【代码】

#include     
#include     
#include     
#include     
#include     
         
int main() {        
    extern int errno;    
    int semid = semget(0x123, 1, 0644|IPC_CREAT|IPC_EXCL);                                                                                            
    if(semid == -1) {    
        printf("semget error!\n");    
        printf("errno: %d\n", errno);    
        perror("result");    
        return -1;    
    }    
    printf("semget success!\n");    
    return 0;    
}

【执行结果】

进程间通信方式(四):System V 信号量_第2张图片
【分析】
        从执行结果来看,当我们第一次运行程序时,成功创建了信号量集。但是,当第二次运行程序后,发现创建失败,errno 被置为17,也就是 EEXIST,错误信息为 File exists,出现这样的结果是因为我们在第一次程序运行后,该信号量集就已经在系统中存在了,而我们在创建信号量集又使用了 IPC_EXCL,这才导致 shmget 出错返回。

2. semctl

  • 【头文件】:#include #include #include
  • 【函数原型】:int semctl(int semid, int semnum, int cmd, ...);
  • 【功能】:获取或设置信号量集的有关信息
  • 【参数】:

        (1)semid:信号量集标识符
        (2)semnum:当前信号量集中的哪一个信号量(下标从0开始)
        (3)cmd:对信号量集要采取的动作

取值 说明
SETVAL 设置信号量集中信号量的计数值
GETVAL 获取信号量集中信号量的计数值
IPC_STAT 读取信号量集的 semid_ds 结构信息,并将其存储在第四个参数 buf 指定的地址空间中
IPC_SET 设置信号量集的 semid_ds 结构信息,这些取值来自于第四个参数 buf 指定地址空间中的参数(需要足够权限)
IPC_RMID 删除信号量集

        (4) :这个参数取决于cmd

  • 【返回值】:成功时具体的返回值依赖于cmd;失败则返回 -1,并将errno设置为错误标识符

【示例】:演示 IPC_STAT 的使用效果
【代码】

#include          
#include      
#include        
#include        
                           
int main() {               
    int semid = semget(0x123, 1, 0644|IPC_CREAT);    
    if(semid == -1) {      
        printf("semget error!\n");    
        return -1;         
    }                      
                           
    struct semid_ds buf;    
    if(semctl(semid, 0, IPC_STAT, &buf) == -1) {                                                                                       
        printf("semctl error!\n");    
        return -1;
    }
    
    printf("buf.sem_perm.mode = %o\n", buf.sem_perm.mode);
    printf("buf.sem_perm.__key = %x\n", buf.sem_perm.__key);
                           
    return 0;              
}

【执行结果】

在这里插入图片描述

3. semop

  • 【头文件】:#include #include #include
  • 【函数原型】:int semop(int semid, struct sembuf *sops, unsigned nsops);
  • 【功能】:对信号量集中的信号量进行 PV 操作
  • 【参数】:

        (1)semid:信号量集标识符
        (2)sops:指向存储信号操作结构的数组指针
        (3)nsops:进行操作信号量的个数

  • 【返回值】:成功时返回 0;失败则返回 -1,并将errno设置为错误标识符

五、综合应用

你可能感兴趣的:(系统编程)