7. 운영체제 - 프로세스 간 통신(5)(세마포어)

1. 기본 지식

1. 여러 프로세스나 스레드가 동시에 액세스할 수 있는 리소스(변수, 연결 목록, 파일 등)를 공유 리소스라고 하며 중요 리소스라고도 합니다.

2. 이러한 리소스에 액세스하는 코드를 크리티컬 코드라고 하며 이러한 코드 영역을 크리티컬 영역이라고 합니다.

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(세마포어 관련 속성 가져오기 또는 설정)

 3. 단계

4. 코드

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