Operating System Concepts 项目:生产者-消费者问题 线程

时间:2021-11-29 09:27:44

 一. 实验目的

      实现一个c程序,该程序能模拟解决有限缓冲问题,其中消费者和生产者产生和消耗随机数

二.实验内容

  1. 缓冲区

元数据类型为buffer_item,大小为1000的数组,按环形队列处理

  1. 生产者和消费者线程

生产者不断执行如下两个操作:消费一个随机数,生产两个随机数

消费者不断执行如下两个操作:生产一个随机数,消费两个随机数

3.Pthead线程创建

使用pthread_create创建5个生产者线程,5个消费者线程,主程序等待所有线程退出

三. 实验环境

      Ubuntu Gnome 14.04

       MinGW 4.8.1

       Codeblocks 13.12

四.实验结果

基本采用semaphore实现了题目要求,其中

psem用于标示是否可生产(数量是否超过缓冲区大小),初始量为1000,每次消费+1,

csem用于标示是否可消费,初始量为0,每次生产+1,

sem用于标示是否可以修改缓冲区

但是以下情况会发生,导致程序死锁:

例如:5个消费者生产5个随机数,随后消耗这5个随机数,则生产者无法先消耗随机数再生产

五.附录

调试心得:
1.  有限缓冲问题确实可能死锁
2.  Pthread_create(tid,attr,func_name,arg)最后一个参数表示唯一传给线程的参数
3.  Void *func_name(void *arg)return需要用pthread_exit(),这个函数的作用是,终止调用它的线程并返回一个指向某个对象的指针,但是直接调用exit(0)会使整个进程退出. 如果主线程调用了pthread_exit,那么它退出了,子线程也不会退出。如果是return 0则会直接退出.
4.  使用函数pthread_exit退出线程,这是线程的主动行为;由于一个进程中的多个线程是共享数据段的,因此通常在线程退出之后,退出线程所占用的资源并不会随着线程的终止而得到释放,但是可以用pthread_join()函数来同步并释放资源。在Linux中,默认情况下是在一个线程被创建后,必须使用此函数对创建的线程进行资源回收,但是可以设置Threads attributes来设置当一个线程结束时,直接回收此线程所占用的系统资源
5.  在线程函数在编译时,需要连接库函数, -lpthread
 
#include <stdio.h>
#include
<pthread.h>
#include
<semaphore.h>
#include
<cstdlib>
#include
<cstring>
using namespace std;
typedef
int item;
const int bsize = 1000;
const int pnum = 5;
const int cnum = 10;
const int looptimes = 10000;
sem_t sem,psem,csem;


struct que{
item a[bsize];
int head,tail,n;
que(){
memset(a,
0,sizeof(a));
head
=tail=n=0;
}
}q;

void p(char * str,int num){
while(num--){
sem_wait(
&psem);
sem_wait(
&sem);
q.a[q.head]
=rand()%10;
q.n
++;
printf(
"%s: produce a[%d]:%d, now there is %d numbers in queue\n",str,q.head,q.a[q.head],q.n);
q.head
=(q.head+1)%bsize;
sem_post(
&csem);
sem_post(
&sem);
}
}

void c(char *str,int num){
while(num--){
sem_wait(
&csem);
sem_wait(
&sem);
q.n
--;
printf(
"%s: consume a[%d]:%d, now there is %d numbers in queue\n",str,q.tail,q.a[q.tail],q.n);
q.tail
=(q.tail+1)%bsize;
sem_post(
&psem);
sem_post(
&sem);
}
}

void * producer(void * arg){
for(int i=0;i<looptimes;i++){
c((
char*)arg,1);
p((
char*)arg,2);
}
pthread_exit(
0);
}
void * consumer(void * arg){
for(int i=0;i<looptimes;i++){
p((
char*)arg,1);
c((
char*)arg,2);
}
pthread_exit(
0);
}
int main(){
sem_init(
&sem,0,1);
sem_init(
&psem,0,1000);
sem_init(
&csem,0,0);
char pname[5][3]={"p1","p2","p3","p4","p5"};
char cname[5][3]={"c1","c2","c3","c4","c5"};
pthread_t ptid[
5],ctid[5];
pthread_attr_t pattr[
5],cattr[5];
for(int i=0;i<5;i++){
pthread_attr_init(pattr
+i);
pthread_create(ptid
+i,pattr+i,producer,pname[i]);
pthread_attr_init(cattr
+i);
pthread_create(ctid
+i,cattr+i,consumer,cname[i]);
}
for(int i=0;i<5;i++){
pthread_join(ptid[i],NULL);
pthread_join(ctid[i],NULL);
}
puts(
"end");
return 0;
}