一. 实验目的
实现一个c程序,该程序能模拟解决有限缓冲问题,其中消费者和生产者产生和消耗随机数
二.实验内容
- 缓冲区
元数据类型为buffer_item,大小为1000的数组,按环形队列处理
- 生产者和消费者线程
生产者不断执行如下两个操作:消费一个随机数,生产两个随机数
消费者不断执行如下两个操作:生产一个随机数,消费两个随机数
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 = ;
const int pnum = ;
const int cnum = ;
const int looptimes = ;
sem_t sem,psem,csem; struct que{
item a[bsize];
int head,tail,n;
que(){
memset(a,,sizeof(a));
head=tail=n=;
}
}q; void p(char * str,int num){
while(num--){
sem_wait(&psem);
sem_wait(&sem);
q.a[q.head]=rand()%;
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+)%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+)%bsize;
sem_post(&psem);
sem_post(&sem);
}
} void * producer(void * arg){
for(int i=;i<looptimes;i++){
c((char*)arg,);
p((char*)arg,);
}
pthread_exit();
}
void * consumer(void * arg){
for(int i=;i<looptimes;i++){
p((char*)arg,);
c((char*)arg,);
}
pthread_exit();
}
int main(){
sem_init(&sem,,);
sem_init(&psem,,);
sem_init(&csem,,);
char pname[][]={"p1","p2","p3","p4","p5"};
char cname[][]={"c1","c2","c3","c4","c5"};
pthread_t ptid[],ctid[];
pthread_attr_t pattr[],cattr[];
for(int i=;i<;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=;i<;i++){
pthread_join(ptid[i],NULL);
pthread_join(ctid[i],NULL);
}
puts("end");
return ;
}