C/C++ Linux 不同进程信号量及数据共享-生产者消费者问题

此为华南理工大学操作系统实验三,by 2020 Network Engineering VK,详情如下:

实验要求:

1.生产者消费者问题(信号量)

参考教材中的生产者消费者算法,创建5个进程,其中两个进程为生产者进程,3个进程为消费者进程。一个生产者进程试图不断地在一个缓冲中写入大写字母,另一个生产者进程试图不断地在缓冲中写入小写字母。3个消费者不断地从缓冲中读取一个字符并输出。为了使得程序的输出易于看到结果,仿照的实例程序,分别在生产者和消费者进程的合适的位置加入一些随机睡眠时间。

可选的实验:在上面实验的基础上实现部分消费者有选择地消费某些产品。例如一个消费者只消费小写字符,一个消费者只消费大写字母,而另一个消费者则无选择地消费任何产品。消费者要消费的产品没有时,消费者进程被阻塞。注意缓冲的管理。


实现思路:

信号量:

采用semaphore.h,头文件各函数详细说明可参考此页<semaphore.h> (opengroup.org),英文难看看不懂可看这个博客semaphore – 简书 (jianshu.com),注意点:init时注意要设置为进程间作用,而不是限制于同一进程内。

数据共享:

摸索许久,没有像多线程编程那样的直接变量共享方法,最后采用了共享内存,使用方法参考博客:Linux进程间通信(六):共享内存 shmget()、shmat()、shmdt()、shmctl() – 52php – 博客园 (cnblogs.com),如果不是深入了解的话,此博客直接看共享内存怎么用就行

程序执行:

将要读写共享内存时流程如下:

尝试获取信号量—>读/写共享内存—>归还信号量


源码:

希望大家可以从我的源码中获得收获/学习,而不是直接复制粘贴应付实验。

头文件

shmdata.h

#ifndef _SHMDATA_H_HEADER
#define _SHMDATA_H_HEADER
 
 
struct shared_use_st
{
    int Acounter; // 大写计数
    int acounter; // 小写计数
};

主程序:

#include <iostream>
#include <unistd.h>  
#include <stdio.h> 
#include <semaphore.h>
#include <sys/shm.h>
#include "shmdata.h"
using namespace std;
int main()
{
    pid_t fpid;
    int fatherpid = getpid();
    sem_t sm;
    sem_init(&sm, 1, 1);

    void *shm = NULL;
    struct shared_use_st *shared; // 指向shm

    // 创建共享内存
    int shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);
    if (shmid == -1)
    {
        fprintf(stderr, "创建共享内存失败\n");
        exit(EXIT_FAILURE);
    }


    // 创建子进程
    for (int i = 0; i < 5; ++i)
    {
        fpid = fork();   //返回子进程的进程ID
        if (fpid == 0 || fpid < 0)
        {
            break;
        }
    }


    // 将共享内存连接到当前进程的地址空间
    shm = shmat(shmid, 0, 0);
    if (shm == (void *)-1)
    {
        fprintf(stderr, "共享内存连接失败\n");
        exit(EXIT_FAILURE);
    }
    printf("\n共享内存连接至 %X\n", (int*)shm);

    // 设置共享内存
    shared = (struct shared_use_st*)shm; // 注意:shm有点类似通过 malloc() 获取到的内存,所以这里需要做个 类型强制转换

    // 根据子进程的身份不同,安排任务
    if (fpid <= 0)
    // 子进程处理
    {
        int diff = getpid() - fatherpid;
        if (diff % 2 == 0)
        // 生产者
        {
            if (diff == 2)
            // 生产大写字母A
            {
                while(1)
                {
                    sem_wait(&sm);     //获取资源 ,相当于P操作
                    shared->Acounter = shared->Acounter + 1;
                    cout << "A生产者 A:\t" << shared->Acounter << "\ta:" << shared->acounter << endl;
                    sem_post(&sm);    //释放资源,相当于V操作
                    sleep(1);
                }
            }else
            // 生产小写字母a
            {
                while(1)
                {
                    sem_wait(&sm);     //获取资源 ,相当于P操作
                    shared->acounter = shared->acounter + 1;
                    cout << "a生产者 A:\t" << shared->Acounter << "\ta:" << shared->acounter << endl;
                    sem_post(&sm);    //释放资源,相当于V操作
                    sleep(1);
                }
            }
        }else
        // 消费者
        {
            if (diff == 1)
            // A消费者
            {
                while(1)
                {
                    sem_wait(&sm);     //获取资源 ,相当于P操作
                    if (shared->Acounter > 0)
                    {
                        shared->Acounter = shared->Acounter - 1;
                        cout << "A消费者 A:\t" << shared->Acounter << "\ta:" << shared->acounter << endl;                        
                    }
                    sem_post(&sm);    //释放资源,相当于V操作
                    sleep(1);
                }               
            }
            else if (diff == 3)
            // a消费者
            {
                while(1)
                {
                    sem_wait(&sm);     //获取资源 ,相当于P操作
                    if (shared->acounter > 0)
                    {
                        shared->acounter = shared->acounter - 1;
                        cout << "a消费者 A:\t" << shared->Acounter << "\ta:" << shared->acounter << endl;
                    }
                    sem_post(&sm);    //释放资源,相当于V操作
                    sleep(1);
                }
            }
            else if (diff == 5)
            // aA消费者
            {
                while(1)
                {
                    sem_wait(&sm);     //获取资源 ,相当于P操作
                    if (shared->Acounter > 0)
                    {
                        shared->Acounter = shared->Acounter - 1;
                        cout << "aA消费者 A:\t" << shared->Acounter << "\ta:" << shared->acounter << endl;
                    }else if (shared->acounter > 0)
                    {
                        shared->acounter = shared->acounter - 1;
                        cout << "aA消费者 A:\t" << shared->Acounter << "\ta:" << shared->acounter << endl;
                    }
                    sem_post(&sm);    //释放资源,相当于V操作
                    sleep(1);
                }                
            }
        }
    }else
    // 父进程处理
    {
        cout << "父进程" << getpid() << endl;
    }
    return 0;
}

运行截图:

发表回复