您当前的位置: 首页 >  操作系统

小天才才

暂无认证

  • 0浏览

    0关注

    168博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【操作系统实验】Linux环境下用进程实现生产者消费者问题——C语言完整代码+详细实验报告

小天才才 发布时间:2021-03-14 20:24:25 ,浏览量:0

【注意】代码在文末,以下为详细实验报告

【实验目的】

  以生产者和消费者问题为例,学习并熟悉Linux下进程通信、同步机制的具体实现方法,主要是了解并掌握信号量机制和共享内存的使用方法,进一步熟悉Linux系统的相关指令的调用。

【实验内容】   使用共享内存和信号量机制来实现生产者和消费者进程间的一对一、一对多和多对多的通信和同步,要求在Linux下实现。

【实验环境】(含主要设计设备、器材、软件等) 在这里插入图片描述

【实验步骤、过程】(含原理图、流程图、关键代码,或实验过程中的记录、数据等)

一、数据结构

1.共享内存定义为一个结构,使得其数据成员更清晰且操作变得简单。 2.共享缓冲区采用循环队列的数据结构,如下图所示。 在这里插入图片描述         图1 共享缓冲区数据结构

  其中,head为队头指针,tail为队尾指针,str[MAX_BUFFER_SIZE]为数据区域,num为数据数量,is_empty为一个标志,用来指明缓冲区是否为空。

二、算法描述

大致可以分为以下四个部分

1.主程序(main)

(1)创建信号量、共享内存并初始化,将申请的共享内存附加到申请通信的进程空间 在这里插入图片描述           图2 初始化参数和信号量

(2)创建生产者、消费者进程,并执行 (3)等待所有子进程结束 (4)删除信号量和共享内存,释放空间

2.生产者进程

(1)通过shmat函数连接共享内存标识符为shm_id的共享内存,把共享内存区对象映射到该生产者进程的地址空间 在这里插入图片描述           图3 生产者进程—连接共享内存

(2)P(SEM_EMPTY),P(MUTEX),product,V(MUTEX),V(SEM_FULL) 在这里插入图片描述           图4 生产者进程—生产

(3)解除和共享内存的关联 在这里插入图片描述           图5 生产者进程—解除关联

3.消费者进程

(1)通过shmat函数连接共享内存标识符为shm_id的共享内存,把共享内存区对象映射到该生产者进程的地址空间 在这里插入图片描述           图6 消费者进程—连接共享内存

(2)P(SEM_FULL),P(MUTEX),product,V(MUTEX),V(SEM_EMPTY) 在这里插入图片描述           图7 消费者进程—消费

(3)解除和共享内存的关联 在这里插入图片描述           图8 消费者进程—解除关联

4.循环队列部分 在这里插入图片描述           图9 循环队列—加入数据 在这里插入图片描述           图10 循环队列—取出数据

5.原子操作

  P操作、V操作对封装的信号量进行“减1”“加1”操作。   在LINUX下,通过使用 semop 函数改变信号量的值。以下P、V操作分别使用两种代码书写方式。 在这里插入图片描述           图11 wait函数(P操作) 在这里插入图片描述           图12 signal函数(V操作)

三、程序流程图

1.主程序流程图 在这里插入图片描述           图13 主程序流程图

2.生产者和消费者进程流程图 在这里插入图片描述 在这里插入图片描述

          图14 生产者和消费者进程流程图

四、编译指令

//1对1
$ gcc -o pro(1)_con(1).out pro(1)_con(1).c
$ ./pro(1)_con(1).out

//1对多
$ gcc -o pro(1)_con(n).out pro(1)_con(n).c
$ ./pro(1)_con(n).out

$ gcc -o pro(n)_con(1).out pro(n)_con(1).c
$ ./pro(n)_con(1).out
//多对多
$ gcc -o pro(n)_con(n).out pro(n)_con(n).c
$ ./pro(n)_con(n).out

图15 所有编译指令

五、运行结果 1.一个生产者+一个消费者 在这里插入图片描述           图16 pro(1)-con(1).c运行结果 2.一个生产者+多个消费者(这里选3个消费者) 在这里插入图片描述           图17 pro(1)-con(n).c运行结果 3.多个生产者(这里选4个生产者)+一个消费者 在这里插入图片描述           图18 pro(n)-con(1).c运行结果 4.多个生产者(这里选5个生产者)+多个消费者(这里选5个消费者) 在这里插入图片描述           图19 pro(n)-con(n).c运行结果

【实验结果或总结】(对实验结果进行相应分析,或总结实验的心得体会,并提出实验的改进意见)

  本次实验是关于生产者和消费者之间互斥和同步的问题。问题的实质是P, V操作,实验设一个共享缓冲区,生产者和消费者互斥的使用,当一个线程使用缓冲区的时候,另一个让其等待知道前一个线程释放缓冲区为止。   生产者消费者问题是互相合作进程关系的一种抽象,例如,在输入时,输入进程是消费者,计算进程是生产者,在输出时,计算进程是生产者,打印进程是消费者,因此该问题很大的代表性和使用价值,也是操作系统在学习进程间同步与互斥的经典问题。   通过本次实验,我对操作系统的P,V进一步的认识,深入的了解P,V操作的实质和其重要性。课本的理论知识进一步阐述了现实的实际问题。

【代码】

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define MAX_BUFFER_SIZE 10
#define SHM_MODE 0600
#define SEM_MODE 0600

#define SEM_FULL 0     //semaphore 1 --- full
#define SEM_EMPTY 1    //semaphore 2 --- empty 
#define MUTEX 2        //semaphore 3 --- exclusive access

struct my_buffer //circular queue
{
	int head;
	int tail;
	char str[MAX_BUFFER_SIZE];
	int num; //number of letter
	int is_empty;
};

const int N_CONSUMER = 5;
const int N_PRODUCER = 5;
const int N_BUFFER = 10;
const int N_WORKTIME = 10;
int shm_id = -1;
int sem_id = -1;
pid_t child; //process type
pid_t parent; //process type


int get_rand_num() //0~9 random number
{
    int digit;
    srand((unsigned)(getpid() + time(NULL)));
    digit = rand() % 10;
    return digit;
}


char get_rand_letter() //A~Z random letter
{
    char letter;
    srand((unsigned)(getpid() + time(NULL)));
    letter = (char)((rand() % 26) + 'A');
    return letter;
}

/*
struct sembuf
{
    unsigned short int sem_num;    //semaphore sequence number
    short int sem_op;              //operation: >0 or =0 or tail = 0;
    bf->is_empty = 1;
    bf->num = 0;
    
    //gcc not allow for(int i=0;...)
    int i,j;
    for(i = 0; i tail = (bf->tail + 1) % MAX_BUFFER_SIZE;
                bf->is_empty = 0;
                bf->num++;

                printTime();
                //printf buffer
                int p;
                printf("buffer data (%d letters):",bf->num);
                p = (bf->tail-1 >= bf->head) ? (bf->tail-1) : (bf->tail-1 + MAX_BUFFER_SIZE);
                
                for (p; !(bf->is_empty) && p >= bf->head; p--)
                {
                    printf("%c", bf->str[p % MAX_BUFFER_SIZE]);
                }
                //printf message
                printf("\nproducer %d puts '%c'.\n", i + 1, c);
                printf("-------------------------------------------------------------\n");
                //flush buffer
                fflush(stdout);
                Signal(sem_id, MUTEX);
                Signal(sem_id, SEM_FULL);
            }
            //disconnect the shared segment from the process
            shmdt(bf);
            exit(0);
        }
    }

    for(i = 0; i head = (bf->head + 1) % MAX_BUFFER_SIZE;
                bf->is_empty = (bf->head == bf->tail); 
                bf->num--;

                printTime();
                //printf buffer
                int p;
                printf("buffer data (%d letters):",bf->num);
                p = (bf->tail-1 >= bf->head) ? (bf->tail-1) : (bf->tail-1 + MAX_BUFFER_SIZE);
                for (p; !(bf->is_empty) && p >= bf->head; p--)
                {
                    printf("%c", bf->str[p % MAX_BUFFER_SIZE]);
                }
                //printf message
                printf("\nconsumer %d gets '%c'.\n", i + 1, lt);
                printf("-------------------------------------------------------------\n");
                //flush buffer
                fflush(stdout);
                Signal(sem_id,MUTEX);
                Signal(sem_id,SEM_EMPTY);
            }
            //disconnect the shared segment from the process
            shmdt(bf);
            exit(0);
        }
    }
    //main process quit
    while (wait(0) != -1);
    //disconnect the shared segment from the process
    shmdt(bf);

    shmctl(shm_id,IPC_RMID,0);
    shmctl(sem_id,IPC_RMID,0);
    printf("the main process is over !\n");
    fflush(stdout);
    exit(0);
    return 0;
}

关注
打赏
1658396332
查看更多评论
立即登录/注册

微信扫码登录

2.1662s