7、操作系统——进程间通信(5)(信号量)

一、基础知识

1、多个进程或线程有可能同时访问的资源(变量、链表、文件等等)称为共享资源, 也叫临界资源(critical resources)。

2、访问这些资源的代码称为临界代码,这些代码区域称为临界区(critical zone)。

3、P操作:程序进入临界区之前必须要对资源进行申请。

4、V操作:程序离开临界区之后必须要释放相应的资源。

 

 二、API

1、semget(获取信号量的ID)

 2、semop(对信号量进行P/V操作,或者等零操作)

(1)信号量操作结构体的定义如下

1 struct sembuf
2 {
3 unsigned short sem_num; /* 信号量元素序号(数组下标) */
4 short sem_op; /* 操作参数 PV 操作 */
5 short sem_flg; /* 操作选项 */
6 };

(2)注意:信号量元素的序号从 0 开始,实际上就是数组下标

(3)根据 sem_op 的数值,信号量操作分成 3 种情况:

        a、sem_op > 0:表示释放信号量,值的大小表示释放的信号量的个数;

        b、sem_op = 0:程序阻塞,直到信号量的值变为0;

        c、sem_op < 0:其绝对值表示程序想要获取的信号量的数量,如果此时 sem_num 指定的信号量没有足够的数量,那么程序将阻塞。

3、semctl(获取或者设置信号量的相关属性)

 三、步骤

四、代码

1、写数据

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <stdlib.h>

union semun
{
    int val; /* 当 cmd 为 SETVAL 时使用 */
    struct semid_ds *buf; /* 当cmd为IPC_STAT 或IPC_SET 时使用 */
    unsigned short *array; /* 当 cmd 为 GETALL 或 SETALL 时使用 */
    struct seminfo *__buf;/* 当 cmd 为 IPC_INFO 时使用 */
};

char * shm_init( void )
{
    // 获取key值
    int key = ftok("./" , 'X');

    // 获取SHM 的ID 
    int shm_id = shmget(key , 4096 , IPC_CREAT | 0644 );
    if (-1 == shm_id )
    {
        perror("shmget id error");
        exit(1); // 直接结束程序(退出进程)
    }

    // 映射共享内存
    char * shm_map = shmat(shm_id ,  NULL , 0 );
    if ((void *) -1 == shm_map)
    {
        perror("shm map error");
        exit(1); // 直接结束程序(退出进程)
    }
    
    return shm_map ;
}

int sem_init(void)
{
    // 获取一个新的key值
    int key = ftok("./" , 'V');

    // 获取 信号量的ID 
    int sem_id =  semget(key, 2 , IPC_CREAT | 0644 );
    if (-1 == sem_id)
    {
        perror("sem get id error ");
        exit(1);
    }

    // 初始化信号量的内容  主要是初始化它们的初始的资源数
    // 初始化为没有数据 , 有一个空间
    union semun set;

    set.val = 0 ;
    semctl(sem_id , 0, SETVAL , set ); // 初始化数据资源 为 0 

    set.val = 1 ;
    semctl(sem_id , 1, SETVAL , set); // 初始化空间资源 为 1

    return sem_id ;
}

int main(int argc, char const *argv[])
{
    // 先搞定共享内存并初始化
    char * shm_map = shm_init();

    // 初始化信号量
    int sem_id = sem_init();

    // 在写入共享内存之前需要先申请一个空间资源  
    struct sembuf space ={
        .sem_num = 1 ,  // 需要设置的空间资源的元素下标为 1 
        .sem_flg = 0 , // 设置标记为 0 啥也不选
        .sem_op = -1  // -1 表示资源量即将-1  申请资源 
    };

    struct sembuf data ={
        .sem_num = 0 ,  // 需要设置的空间资源的元素下标为 1 
        .sem_flg = 0 , // 设置标记为 0 啥也不选
        .sem_op = 1  // 1 表示资源量即将加1  释放资源 
    };


    while(1)
    {
        // 等待空间资源  如果资源暂时不能得到则会阻塞等待(睡眠)
        printf("正在等待空间进行写入数据!!!\n");
        semop(sem_id , &space , 1 );
        printf("已经得到空间, 正在写入数据!!!\n");


        printf("请输入需要发送的数据:\n");
        fgets(shm_map , 4096 , stdin);
        
        // 设置 数据资源为1
        printf("设置数据为 1  \n"); 
        semop(sem_id , &data , 1 );

    }

    return 0;
}

2、读数据

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <stdlib.h>

union semun
{
    int val; /* 当 cmd 为 SETVAL 时使用 */
    struct semid_ds *buf; /* 当cmd为IPC_STAT 或IPC_SET 时使用 */
    unsigned short *array; /* 当 cmd 为 GETALL 或 SETALL 时使用 */
    struct seminfo *__buf;/* 当 cmd 为 IPC_INFO 时使用 */
};

char * shm_init( void )
{
    // 获取key值
    int key = ftok("./" , 'X');

    // 获取SHM 的ID 
    int shm_id = shmget(key , 4096 , IPC_CREAT | 0644 );
    if (-1 == shm_id )
    {
        perror("shmget id error");
        exit(1); // 直接结束程序(退出进程)
    }

    // 映射共享内存
    char * shm_map = shmat(shm_id ,  NULL , 0 );
    if ((void *) -1 == shm_map)
    {
        perror("shm map error");
        exit(1); // 直接结束程序(退出进程)
    }
    
    return shm_map ;
}

int sem_init(void)
{
    // 获取一个新的key值
    int key = ftok("./" , 'V');

    // 获取 信号量的ID 
    int sem_id =  semget(key, 2 , IPC_CREAT | 0644 );
    if (-1 == sem_id)
    {
        perror("sem get id error ");
        exit(1);
    }

    // 初始化信号量的内容  主要是初始化它们的初始的资源数
    // 初始化为没有数据 , 有一个空间
    union semun set;

    set.val = 0 ;
    semctl(sem_id , 0, SETVAL , set ); // 初始化数据资源 为 0 

    set.val = 1 ;
    semctl(sem_id , 1, SETVAL , set); // 初始化空间资源 为 1

    return sem_id ;
}

int main(int argc, char const *argv[])
{
    // 先搞定共享内存并初始化
    char * shm_map = shm_init();

    // 初始化信号量
    int sem_id = sem_init();

    // 在写入共享内存之前需要先申请一个空间资源  

    // struct sembuf
    // {
    //     unsigned short sem_num; /* 信号量元素序号(数组下标) */
    //     short sem_op; /* 操作参数 */
    //     short sem_flg; /* 操作选项 */
    // };
    struct sembuf space ={
        .sem_num = 1 ,  // 需要设置的空间资源的元素下标为 1 
        .sem_flg = 0 , // 设置标记为 0 啥也不选
        .sem_op = 1  // 1 表示资源量即将加1  申请资源 
    };

    struct sembuf data ={
        .sem_num = 0 ,  // 需要设置的空间资源的元素下标为 1 
        .sem_flg = 0 , // 设置标记为 0 啥也不选
        .sem_op = -1  // -1 表示资源量即将 减1  释放资源 
    };


    while(1)
    {
        // 等待数据资源  如果资源暂时不能得到则会阻塞等待(睡眠)
        printf("正在等待数据的到达!!!\n");
        semop(sem_id , &data , 1 );
        printf("数据已经到达!!!\n");


        printf("Jack 说:%s\n" , shm_map );
        // fgets(shm_map , 4096 , stdin);
        
        // 设置 空间资源为1 
        sleep(2);
        printf("数据处理结束 , 设置空间为 1  !!!\n");
        semop(sem_id , &space , 1 );

    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45981798/article/details/129783560
今日推荐