生产者消费者问题模拟(Pthread-C-Linux-输出环形队列)

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6


生产者消费者问题

  • 课题报告与要求
  • 概要设计
  • 程序执行过程图
  • 源程序代码
  • 主函数
  • "Out_Print.h"文件
  • 执行结果
  • 运行说明:NUMBER XX:表示此处运行的行号,后面的0~9表示缓冲区的位置,如果缓冲区的位置显示“#”表示此处有产品。
  • 调试过程中的问题
  • sem_wait是一个函数,也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。类似于P操作
  • sem_post是给信号量的值加上一个“1”,它是一个“原子操作”。 当有线程阻塞在这个信号量上时,调用这个函数会使其中一个线程不在阻塞,选择机制是由线程的调度策略决定的。类似于V操作
  • 当pthread_mutex_lock()返回时,该互斥锁已被锁定。线程调用该函数让互斥锁上锁,如果该互斥锁已被另一个线程锁定和拥有,则调用该线程将阻塞,直到该互斥锁变为可用为止。
  • pthread_mutex_unlock是可以解除锁定 mutex 所指向的互斥锁的函数
  • Q1:在两个消费者和两个生产者的条件下,同时生产者每生产一个就sleep(1),而消费者每消费一个就sleep(2),这个运行到一会的结果是在满缓冲区和满缓冲区-1这个数量运行,因为生产者生产的快,而消费者消费的较慢。符合预期。P1如果将消费者的睡眠时间减少,并且生产者睡眠调高。即,生产者每生产一个就sleep(2),而消费者每消费一个就sleep(1),最终的实验结果是生产者刚生产一个,就消费了P2,这两个是两个极端,没有呈现运行结果的随机性,这里就是的睡眠时间都是确定的,这里为了人为的让其呈现出随机性,有两个方法。1、创建生产者的数量与消费者的数量相差很大,2、每次生产者消费者睡眠的时间是一个随机数。从而呈现出一定的随机性。其运行结果符合预期。
  • Q2:就是环形队列的输出问题,这个需要分情况讨论,不能一概而论的输出结果。

课题报告与要求

生产者消费者问题(Producer-consumer problem)是一个经典的进程同步。该问题描述了共享固定大小缓冲区的两类进程——即所谓的“生产者”进程和“消费者”进程——在实际运行时会发生的问题。生产者进程的主要作用是生成一定量的数据(产品)并将这些数据(产品)放到缓冲区中,然后重复此过程。与此同时,消费者进程重复执行从缓冲区中取数据(产品)并消耗这些数据(产品)。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时取数据。
在Linux平台下编程实现生产者消费者进程的模拟,要求:

  1. (1) 创建3个进程——1个生产者进程(PA进程),2个消费者进程(CA进程和CB进程)。
  2. (2) 需要两个共享内存——array和get,array[0…4]是共享的5个缓冲区,get是消费者进程已取产品计数。
  3. (3) 使用到三个信号量——empty、full、mutex,其中empty和full用于进程的同步,mutex用于进程对缓冲区操作的互斥。
  4. (4) 生产者进程PA生产10个产品,并放入缓冲区array中,消费者进程(CA和CB进程)从缓冲区array中共取10个产品。
  5. (5) 需要熟悉进程创建的系统调用,即fork系统调用。需要熟悉共享内存的相关系统调用,即shm开头的一组系统调用。需要熟悉信号量的相关系统调用,即sem开头的一组系统调用。
  6. (6) 可根据自己能力,在完成以上基本要求后,对程序功能进行扩充。

概要设计

基础的生产消费线程实现同步的过程如下图所示
其中P(),V()操作分别使用头文件semaphore.h中的函数sem_wait(),sem_post()。Lock()和unlock()分别使用头文件pthread.h中的pthread_mutex_lock()和pthread_mutex_unlock()函数。设计的四个操作的函数说明如下:
(1) sem_wait是一个函数,也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。类似于P操作
(2)sem_post是给信号量的值加上一个“1”,它是一个“原子操作”。 当有线程阻塞在这个信号量上时,调用这个函数会使其中一个线程不在阻塞,选择机制是由线程的调度策略决定的。类似于V操作
(3)当pthread_mutex_lock()返回时,该互斥锁已被锁定。线程调用该函数让互斥锁上锁,如果该互斥锁已被另一个线程锁定和拥有,则调用该线程将阻塞,直到该互斥锁变为可用为止。
(4)pthread_mutex_unlock是可以解除锁定 mutex 所指向的互斥锁的函数。

程序执行过程图

生产者消费者问题模拟(Pthread-C-Linux-输出环形队列)_互斥锁

源程序代码

主函数

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>
#include "Out_Print.h"
#define BUFFER 10
int in = 0, out = 0;
int t = 0;
int buffer[10];
int get_srand();       //Return random number
sem_t empty,full;
pthread_mutex_t mutex;
pthread_t arr[50];
int num_producer, num_customer;
int get_srand(int range)
{
	int ans;
	srand((unsigned)time(NULL));
	ans = rand()%range+1;  //1~range
	return ans;
}
void*  producer(void* arg)
{
    while(1)
    {
	//will put nextp to buffer
 	//int nextp = get_srand(BUFFER);
            
        sem_wait(&empty); //P
        pthread_mutex_lock(&mutex);
        //add
	++t;
//	printf("producer :  %2d 1 to  %2d	", in, ++t);
	P_out(in, t, 1);
	in = (in + 1)%BUFFER;
	//++t;
	//P_out(t, 1);
        //t++;
        pthread_mutex_unlock(&mutex);
        sem_post(&full);//V
	int wait_time = get_srand(2);
        sleep(wait_time);
    }
}
  
void* customer(void* arg)
{
    while(1)
    {
	    //will custom nextc from buffer
	//int nextc = get_srand(BUFFER);

        sem_wait(&full); //P
        pthread_mutex_lock(&mutex);
	--t;	
//	printf("customer : %2d 1 to  %2d", out, --t);
	V_out(out, t, 1);
	out = (out+1)%BUFFER;
	//--t;
	//V_out(t, 1);
        //t--;
	//printf("customer delete 1 to %d\n", t);
        pthread_mutex_unlock(&mutex);
        sem_post(&empty);//V
	//int wait_time = get_srand(5);
        //sleep(wait_time);
    }
}
  
int main()
{
    printf("input the number of the producer and customer : ");
    scanf("%d%d", &num_producer, &num_customer);
    
    pthread_mutex_init(&mutex, NULL);
    sem_init(&full, 0, 0);
    sem_init(&empty, 0, 10);
    
    for(int i = 0; i < num_producer; ++i)
    {
	    pthread_create(&arr[i], NULL, producer, NULL);
    }
    for(int i = num_producer; i < num_producer+num_customer; ++i)
    {
	    pthread_create(&arr[i], NULL, customer, NULL);
    }
    for(int i = 0; i < num_producer+num_customer; ++i)
    {
	    pthread_join(arr[i], NULL);
    }
    return 0;
}

"Out_Print.h"文件

#include <stdio.h>
#define BUFFER 10
int sum = 0;
void V_out(int out, int t, int number);
void P_out(int in,  int t, int number);
void P_out(int in, int t, int number)
{
	++sum;
	printf("NUMBER %3d 	", sum);
	if(in >= t)
	{
		for(int i = 0; i < BUFFER; ++i)
		{
			if(i > in-t && i <= in)
			{
				printf("#");
			}
			else 
				printf("%d", i);
		}
	}
	else 
	{
		int other = t-(in+1);
		for(int i = 0; i < BUFFER; ++i)
		{
			if(i <= in || (i >= BUFFER-other && i < BUFFER))
			{
				printf("#");
			}
			else 
				printf("%d", i);
		}
	}
	printf("\n");
}
void V_out(int out, int t, int number)
{
	++sum;
	printf("NUMBER %3d 	", sum);
	if(out+t < BUFFER)
	{
		for(int i = 0; i < BUFFER; ++i)
		{
			if(i > out && i <= out+t)
			{
				printf("#");
			}
			else 
				printf("%d", i);
		}
	}
	else
	{
		int other = BUFFER - (out+t);
		for(int i = 0; i < BUFFER; ++i)
		{
			if(i <= other || i > out)
			{
				printf("#");
			}
			else 
				printf("%d", i);
		}
	}
	printf("\n");
}

执行结果

运行说明:NUMBER XX:表示此处运行的行号,后面的0~9表示缓冲区的位置,如果缓冲区的位置显示“#”表示此处有产品。

  • 创建两个生产者和两个消费者线程运行结果:
  • 创建五个生产者和两个消费者线程运行结果:
  • 生产者消费者问题模拟(Pthread-C-Linux-输出环形队列)_互斥锁_02

  • 创建十个生产者和两个消费者线程运行结果:
  • 生产者消费者问题模拟(Pthread-C-Linux-输出环形队列)_信号量_03

调试过程中的问题

sem_wait是一个函数,也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。类似于P操作

sem_post是给信号量的值加上一个“1”,它是一个“原子操作”。 当有线程阻塞在这个信号量上时,调用这个函数会使其中一个线程不在阻塞,选择机制是由线程的调度策略决定的。类似于V操作

当pthread_mutex_lock()返回时,该互斥锁已被锁定。线程调用该函数让互斥锁上锁,如果该互斥锁已被另一个线程锁定和拥有,则调用该线程将阻塞,直到该互斥锁变为可用为止。

pthread_mutex_unlock是可以解除锁定 mutex 所指向的互斥锁的函数

Q1:在两个消费者和两个生产者的条件下,同时生产者每生产一个就sleep(1),而消费者每消费一个就sleep(2),这个运行到一会的结果是在满缓冲区和满缓冲区-1这个数量运行,因为生产者生产的快,而消费者消费的较慢。符合预期。P1如果将消费者的睡眠时间减少,并且生产者睡眠调高。即,生产者每生产一个就sleep(2),而消费者每消费一个就sleep(1),最终的实验结果是生产者刚生产一个,就消费了P2,这两个是两个极端,没有呈现运行结果的随机性,这里就是的睡眠时间都是确定的,这里为了人为的让其呈现出随机性,有两个方法。1、创建生产者的数量与消费者的数量相差很大,2、每次生产者消费者睡眠的时间是一个随机数。从而呈现出一定的随机性。其运行结果符合预期。

Q2:就是环形队列的输出问题,这个需要分情况讨论,不能一概而论的输出结果。


阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: linux