【Linux之进程间通信】08.Linux进程通信 - 信号量集

 
【Linux之进程间通信】

项目代码获取:https://gitee.com/chenshao777/linux-processes.git
(麻烦点个免费的Star哦,您的Star就是我的写作动力!)

08.信号量集

流程:

Created with Raphaël 2.3.0 开始 创建信号集: semget 设置信号属性: semctl+union semun 设置信号操作: semop+struct sembuf 删除信号集: semctl 结束

公共头文件:

#include 
#include 
#include 

1.创建信号量集

int semget(key_t key, int nsems, int semflg);
参数 含义
key 生成semid相关key值
nsems 初始化信号集中信号的个数
semflg 权限

返回值:成功返回信号集ID,失败返回-1

2.设置信号属性 / 删除信号集

int semctl(int semid, int semnum, int cmd, ...);
参数 含义
semid 信号集ID
semnum 信号量编号(从0开始)
cmd 不同任务所需的命令参数
根据cmd决定第四项是否需要

返回值:成功根据cmd返回不同值,失败返回-1
当cmd为 SETVAL 时,表示设置信号属性,则第四个参数类型为 union semun

union semun {
    int              val;    /* 信号值 */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;  /* Array for GETALL, SETALL */
    struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                (Linux-specific) */
};

我们需要关心的主要是联合体中的第一个成员 val
比如,我们要初始化信号集中的第二个信号,将他的初始值初始化为0,代码如下:

/*初始化信号*/
union semun mysemun;
mysemun.val = 0;  
//设置第2个信号(1)
semctl(semid, 1, SETVAL, mysemun);

3.设置信号操作

int semop(int semid, struct sembuf *sops, size_t nsops);
参数 含义
semid 信号集ID
sops 信号操作结构体
nsops 要操作的信号个数

返回值:成功返回0,失败返回-1

其中struct sembuf结构体成员如下:

unsigned short sem_num;  /* 信号量编号 */
short          sem_op;   /* 信号操作(P分配或者V释放) */
short          sem_flg;  /* 阻塞操作 / 非阻塞操作 */

比如我们要分配第二个信号量,且阻塞操作

/*分配信号*/
//设置操作信号的方式(P分配或V释放)
struct sembuf sops;
sops.sem_num = 1;  //要操作的信号量编号
sops.sem_flg = 0;  //阻塞操作       
sops.sem_op = -1;  //分配资源 P操作
semop(semid, &sops, 1);  // 1:操作的信号数为1

4.查看信号集

system("ipcs -s");

5.删除信号集

/*删除信号集*/
semctl(semid, 0, IPC_RMID);

6.进程同步实验

实验说明:client进程先启动,但要等待server进程先运行起来,client进程才开始运行
通过信号机制实现
server.c

#include 
#include 
#include 
#include 
#include 
#include 

/*
    通过信号灯同步两个非亲缘关系进程
    client端先启动,等server端输出十条语句后client端才运行
*/

union semun {
    int              val;    /* Value for SETVAL */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;  /* Array for GETALL, SETALL */
    struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                (Linux-specific) */
};

int main(int argc, char *argv[])
{
    /*初始化信号量集*/
    int key, semid;
    key = ftok("./a.c", 1);
    //初始化一个有3个信号量的信号集
    semid = semget(key, 3, IPC_CREAT | 0777);
    if(semid < 0){
        printf("server信号灯初始化失败!\n");
        return -1;
    }
    printf("server信号灯初始化成功!,semid = %d\n", semid);

    //查看信号集
    system("ipcs -s");

    /*初始化信号*/
    union semun mysemun;
    mysemun.val = 0;  
    //设置第2个信号(1)
    semctl(semid, 1, SETVAL, mysemun);

    /*打印十条语句*/
    for(int i=0;i<10;i++){
        printf("server\n");
    }

    /*分配信号*/
    //设置操作信号的方式(P或V)
    struct sembuf sops;
    sops.sem_num = 1;  //要操作的信号量编号
    sops.sem_flg = 0;  //阻塞操作
    sops.sem_op = 1;  //分配资源 V操作
    semop(semid, &sops, 1);  // 1:操作的信号数为1

    return 0;
}

client.c

#include 
#include 
#include 
#include 
#include 
#include 

/*
    通过信号灯同步两个非亲缘关系进程
    client端先启动,等server端输出十条语句后client端才运行
*/

union semun {
    int              val;    /* Value for SETVAL */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;  /* Array for GETALL, SETALL */
    struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                (Linux-specific) */
};

int main(int argc, char *argv[])
{
    /*初始化信号量集*/
    int key, semid;
    key = ftok("./a.c", 1);
    //初始化一个有3个信号量的信号集
    semid = semget(key, 3, IPC_CREAT | 0777);
    if(semid < 0){
        printf("client信号灯初始化失败!\n");
        return -1;
    }
    printf("client信号灯初始化成功!,semid = %d\n", semid);

    //查看信号集
    system("ipcs -s");

    /*初始化信号*/
    union semun mysemun;
    mysemun.val = 0;  
    //设置第2个信号(1)
    semctl(semid, 1, SETVAL, mysemun);

    /*分配信号*/
    //设置操作信号的方式(P或V)
    struct sembuf sops;
    sops.sem_num = 1;  //要操作的信号量编号
    sops.sem_flg = 0;  //阻塞操作       
    sops.sem_op = -1;  //分配资源 P操作
    semop(semid, &sops, 1);  // 1:操作的信号数为1

    /*休眠1秒,打印十条语句*/
    sleep(1);
    for(int i=0;i<10;i++){
        printf("client\n");
    }

    /*删除信号集*/
    semctl(semid, 0, IPC_RMID);

    //查看信号集
    system("ipcs -s");

    return 0;
}

你可能感兴趣的:(Linux进程间通信,linux,进程通信,信号量,semget,信号灯)