7. Operating system - inter-process communication (5) (semaphore)

1. Basic knowledge

1. Resources (variables, linked lists, files, etc.) that multiple processes or threads may access at the same time are called shared resources, also called critical resources.

2. The code that accesses these resources is called critical code, and these code areas are called critical zones.

3. P operation: Before the program enters the critical section, it must apply for resources.

4. V operation: After the program leaves the critical section, the corresponding resources must be released.

 

 2. API

1. semget (get the ID of the semaphore)

 2. Semop (P/V operation on the semaphore, or equal zero operation)

(1) The definition of the semaphore operation structure is as follows

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

(2) Note: The serial number of the semaphore element starts from 0, which is actually the subscript of the array

(3) According to the value of sem_op, the semaphore operation is divided into three cases:

        a. sem_op > 0: indicates the release of the semaphore, and the size of the value indicates the number of released semaphores;

        b. sem_op = 0: the program blocks until the value of the semaphore becomes 0;

        c. sem_op < 0: Its absolute value indicates the number of semaphores the program wants to acquire. If there  sem_num are not enough semaphores specified at this time, the program will block.

3. semctl (get or set related properties of semaphore)

 3. Steps

4. Code

1. Write data

#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. Read data

#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;
}

 

Guess you like

Origin blog.csdn.net/weixin_45981798/article/details/129783560