Bootstrap

进程间通信方式-共享内存与信号灯集结合练习

实现两个进程一边输入,一边输出,输入quit时结束。

/*

通过信号灯集与共享内存配合,实现输入输出交替进行,做到输入一个输出一个

(1)初始化:零号信号灯初值为0,一号信号灯初值为1

(2)输入部分:申请一号信号灯,可以申请到资源,然后一号信号灯变为0,

输入完成之后,释放零号信号灯,零号信号灯就变为1;

(3)输出部分:申请零号信号灯,刚开始零号信号灯初值为0,无法申请到资源,

只有当输入进程完成输入,把零号信号灯变为1之后,输出进程才可以申请到资源,进行输出,

输入完成之后,释放一号信号灯,让一号信号灯变为1,然后输入进程可以申请资源继续输入

*/

第一部分:输入

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

/*
通过信号灯集与共享内存配合,实现输入输出交替进行,做到输入一个输出一个
(1)初始化:零号信号灯初值为0,一号信号灯初值为1
(2)输入部分:申请一号信号灯,可以申请到资源,然后一号信号灯变为0,
    输入完成之后,释放零号信号灯,零号信号灯就变为1;
(3)输出部分:申请零号信号灯,刚开始零号信号灯初值为0,无法申请到资源,
    只有当输入进程完成输入,把零号信号灯变为1之后,输出进程才可以申请到资源,进行输出,
    输入完成之后,释放一号信号灯,让一号信号灯变为1,然后输入进程可以申请资源继续输入
*/

union semun
{
    int val;
};

// 初始化信号灯集
void init(int semid, int num, int val)
{
    union semun sem;
    sem.val = val;                   // 初始化的值
    semctl(semid, num, SETVAL, sem); // 对编号为num的信号灯初始化为 sem
}

// 信号灯集操作
void pv(int semid, int num, int op)
{
    struct sembuf mysembuf;
    mysembuf.sem_num = num; // 进行操作的信号灯编号
    mysembuf.sem_op = op;   // pv操作
    mysembuf.sem_flg = 0;
    semop(semid, &mysembuf, 1);
}

int main(int argc, char const *argv[])
{
    // 定义信号灯集id与共享内存id
    int shmid;
    int semid;

    // 创建key值
    key_t key;
    key = ftok("semsharein.c", 'd');
    if (key < 0)
    {
        perror("key error");
        return -1;
    }
    printf("key:%#x\n", key);

    // 创建或打开信号灯集
    // 不存在创建,存在返回-1
    semid = semget(key, 2, IPC_CREAT | IPC_EXCL | 0777);
    if (semid <= 0)
    {
        if (errno == EEXIST) // 如果存在,直接打开,返回id
        {
            semid = semget(key, 2, 0777);
        }
        else
        {
            perror("semid error");
            return -1;
        }
    }
    else
    {
        // 初始化信号灯集
        // 若是信号灯集已经被创建,则直接打开,无需重新初始化
        init(semid, 0, 0);
        init(semid, 1, 1);
    }
    printf("semid:%d\n", semid);
    // 获取信号灯值
    printf("%d\n", semctl(semid, 0, GETVAL));
    printf("%d\n", semctl(semid, 1, GETVAL));

    // 创建或打开共享内存
    // 不存在创建,存在返回-1
    shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0777);
    // 如果存在,直接打开,返回id
    if (shmid <= 0)
    {
        if (errno == EEXIST)
        {
            shmid = shmget(key, 128, 0777);
        }
        else
        {
            perror("shmid error");
            return -1;
        }
    }
    printf("shmid:%d\n", shmid);

    // 映射共享内存
    char *p;
    p = (char *)shmat(shmid, NULL, 0);
    if (p == (char *)-1)
    {
        perror("shmat err");
        return -1;
    }

    // 循环向共享内存中写入内容
    while (1)
    {
        // 申请信号灯序号为1的资源,有就申请,没有就阻塞等待
        pv(semid, 1, -1);
        scanf("%s", p);
        // 释放信号灯序号为0的资源
        pv(semid, 0, 1);
        if (strcmp(p, "quit") == 0)
        {
            break;
        }
    }

    // 取消映射
    shmdt(p);

    // 删除共享内存
    shmctl(shmid, IPC_RMID, NULL);

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

    return 0;
}

第二部分:输出

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

union semun
{
    int val;
};

// 初始化信号灯集
void init(int semid, int num, int val)
{
    union semun sem;
    sem.val = val;                   // 初始化的值
    semctl(semid, num, SETVAL, sem); // 对编号为num的信号灯初始化为 sem
}

// 信号灯集操作
void pv(int semid, int num, int op)
{
    struct sembuf mysembuf;
    mysembuf.sem_num = num; // 进行操作的信号灯编号
    mysembuf.sem_op = op;   // pv操作
    mysembuf.sem_flg = 0;
    semop(semid, &mysembuf, 1);
}

int main(int argc, char const *argv[])
{
    int shmid;
    int semid;

    // 创建key值
    key_t key;
    key = ftok("semsharein.c", 'd');
    if (key < 0)
    {
        perror("key error");
        return -1;
    }
    printf("key:%#x\n", key);

    // 创建或打开信号灯集
    // 不存在创建,存在返回-1
    semid = semget(key, 2, IPC_CREAT | IPC_EXCL | 0777);
    if (semid <= 0)
    {
        if (errno == EEXIST) // 如果存在,直接打开,返回id
        {
            semid = semget(key, 2, 0777);
        }
        else
        {
            perror("semid error");
            return -1;
        }
    }
    else
    {
        // 初始化信号灯集
        // 若是信号灯集已经被创建,则直接打开,无需重新初始化
        init(semid, 0, 0);
        init(semid, 1, 1);
    }
    printf("semid:%d\n", semid);
    // 获取信号灯值
    printf("%d\n", semctl(semid, 0, GETVAL));
    printf("%d\n", semctl(semid, 1, GETVAL));

    // 创建或打开共享内存
    // 不存在创建,存在返回-1
    shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0777);
    // 如果存在,直接打开,返回id
    if (shmid <= 0)
    {
        if (errno == EEXIST)
        {
            shmid = shmget(key, 128, 0777);
        }
        else
        {
            perror("shmid error");
            return -1;
        }
    }
    printf("shmid:%d\n", shmid);

    // 映射共享内存
    char *p;
    p = (char *)shmat(shmid, NULL, 0);
    if (p == (char *)-1)
    {
        perror("shmat err");
        return -1;
    }

    // 循环读取共享内存中的内容
    while (1)
    {
        if (strcmp(p, "quit") == 0)
        {
            break;
        }
        // 申请信号灯序号为0的资源,有就申请,没有就阻塞等待
        pv(semid, 0, -1);
        printf("%s\n", p);
        // 释放信号灯序号为0的资源
        pv(semid, 1, 1);
    }

    // 取消映射
    shmdt(p);

    // 删除共享内存
    shmctl(shmid, IPC_RMID, NULL);

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

    return 0;
}

运行效果

 

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;