实验二 消费者生产者模型
1.1实验目的
1.2实验内容
1.3基本概念与原理
1.31 程序设计思想
1.32程序结构
1.33算法程序
1.34程序运行图
一些函数功能
1、库文件:#include
2、数据类型:
pthread_mutex_t //互斥量
pthread_mutexattr_t //互斥量的属性
3、互斥量相关的函数:
①intpthread_mutex_init(pthread_mutex_t*mutex,constpthread_mutexattr_t *attr);//对一个互斥量进行初始化
②intpthread_mutex_destroy(pthread_mutex_t*mutex);//销毁一个互斥量;返回值:成功则返回0,否则返回错误编号
③intpthread_mutex_lock(pthread_mutex_t *mutex);
④intpthread_mutex_trylock(pthread_mutex_t *mutex);
⑤intpthread_mutex_unlock(pthread_mutex_t *mutex);//返回值:成功则返回0,否则返回错误编号;这三个函数用于对互斥量进行加锁解锁。其中pthread_mutex_trylock是非阻塞的加锁函数,若加锁失败,则立即返回EBUSY。
4、示例
//…
pthread_mutex_tmutex;
pthread_mutex_init(&mutex, NULL);
pthread_mutex_lock(&mutex);
//do something
pthread_mutex_unlock(&mutex);
pthread_mutex_destroy(&mutex);
//…
三、POSIX线程函数
1、库文件:#include
2、数据类型:pthread_t;线程ID
3、线程相关函数:
①pthread_tpthread_self();//返回调用线程的线程ID
②intpthread_create(pthread_t *tidp, constpthread_attr_tattr, void *(*start_rtn)(void*), void *arg);//线程创建函数,tidp,用于返回线程ID;attr,线程属性,若设为NULL,则线程使用默认属性;start_rtn是线程例程函数,arg为线程函数参数。
③voidpthread_exit(void *rval_ptr);//rval_ptr指向线程返回值。
线程退出有以下几种情况:
a.线程从例程函数返回。
b.线程被其它线程取消。
c.线程调用pthread_exit()主动退出。
④intpthread_join(pthread_t thread, void **rval_ptr);//返回值:成功返回0,错误返回错误编号;此函数用于等待指定线程(由参数thread指定)运行结束,期间,调用线程将会阻塞。rval_ptr参数用于获取线程返回值。
四、Linux信号量
1、库文件:#include
2、信号量数据类型:sem_t
3、主要函数:
①sem_init(sem_t*sem, int pshared, unsigned int value);//初始化一个无名信号量
②sem_destroy(sem_t*sem);//销毁一个无名信号量;返回值:成功返回 0;错误返回 -1,并设置errno
③sem_post(sem_t *sem);//信号量值加1。若有线程阻塞于信号量sem,则调度器会唤醒对应阻塞队列中的某一个线程。
④sem_wait(sem_t *sem);//若sem小于0,则线程阻塞于信号量sem,直到sem大于0。否则信号量值减1。
⑤sem_trywait(sem_t *sem);//功能同sem_wait(),但此函数不阻塞,若sem小于0,直接返回;返回值:成功返回0,错误返回-1,并设置errno
来源:https://blog.csdn.net/fengjunwang1980/article/details/51789993
使用pthread_join的原因
使用 pthread_create 创建线程后主进程结束,创建的线程也会结束,使用 pthread_join 可以阻塞主线程。
来源:http://www.cnblogs.com/dk666/p/7339081.html
1. 熟悉进程的九种状态,理解并发进程临界资源,互斥和同步资源的差异。
2. 理解掌握P(S)原语和V(S)原语的操作原理,以及信号量S的意义。
3. 理解经典“生产者-消费者”问题。
4. 掌握线程编程解决互斥和同步资源的方法。
1. 设计编写“生产者-消费者”的程序,运行并记录结果。
2. 随机定义生产者进程和消费者进程并发的数量和次序,分析信号量的变化过程,以及线程状态变化过程。
3. 分析信号量设置不合理,会出现什么情况。例如,什么时候会出现无法唤醒一个生产者(或消费者)的情况。
4. 举例说明在现实生活中符合“生产者-消费者模型”的五种情况。
生产者-消费者(producer-consumer)问题是一个经典的进程同步问题,最早由Dijkstra提出,用以演示他提出的信号量机制。生产者-消费者也称作有界缓冲区(bounded-buffer)问题,两个进程共享一个公共的固定大小的缓冲区。其中一个是生产者,用于将消息放入缓冲区;另外一个是消费者,用于从缓冲区中取出消息。问题出现在当缓冲区已经满了,而此时生产者还想向其中放入一个新的数据项的情形,其解决方法是让生产者此时进行休眠,等待消费者从缓冲区中取走了一个或者多个数据后再去唤醒它。同样地,当缓冲区已经空了,而消费者还想去取消息,此时也可以让消费者进行休眠,等待生产者放入一个或者多个数据时再唤醒它。
deposit(data):
begin
P(avail)
P(mutex)
送数据入缓冲区某单元
V(full)
V(mutex)
End
remove(data):
begin
P(full)
P(mutex)
取缓冲区中某单元数据
V(avail)
V(mutex)
end
(1)生产者
生产者 图 1
(2)消费者
消费者 图 2
#include
#include
#include
#include
#include
#define PRODUCER 10//生产者数量
#define CONSUMER 8//消费者数量
#define BUFFER 20//缓冲区数量
sem_t empty,full;//同步信号量
pthread_mutex_t mutex;//互斥信号量
int buffer[BUFFER]; //缓冲区
int producer_id=0,consumer_id=0;//生产者消费者ID
int index_in=0,index_out=0;//生产者 消费者 存放 消费的位置
void print()//输出缓冲区
{
int i;
printf("Buffer:\n");
for(i=0;i<20;i++)
{
printf("___");
}
printf("\n");
for(i=0;i<20;i++)
printf("|%d|",buffer[i]);
printf("\n");
for(i=0;i<20;i++)
{
printf("———");
}
printf("\n");
}
void *Producer()//生产者函数
{
int ID=++producer_id;
while(1)
{
sleep(3);
sem_wait(&empty);
pthread_mutex_lock(&mutex);
index_in=index_in%BUFFER;
printf("Producer %d in %d.\n",ID,index_in);
buffer[index_in]=1;//缓冲区置0
print();//输出缓冲区情况
index_in++;
pthread_mutex_unlock(&mutex);
sem_post(&full);
}
}
void *Consumer()//消费者函数
{
int ID=++consumer_id;
while(1)
{
sleep(3);
sem_wait(&full);
pthread_mutex_lock(&mutex);
index_out=index_out%BUFFER;
printf("\033[01;34mConsumer %d in %d\033[0m\n",ID,index_out);
buffer[index_out]=0;//缓冲区置0
print();//输出缓冲区情况
index_out++;
pthread_mutex_unlock(&mutex);
sem_post(&empty);
}
}
int main()
{
//freopen("text.txt","w",stdout);
int rthread[18],i;
pthread_t producer[PRODUCER];//生产者
pthread_t consumer[CONSUMER];//消费者
int sinit1=sem_init(&empty,0,BUFFER);//初始化同步信号量
int sinit2=sem_init(&full,0,0);
int minit =pthread_mutex_init(&mutex,NULL);//初始化互斥信号量
if(sinit1 && sinit2)
{
printf("sem initialize failed /n");
exit(1);
}
if(minit)
{
printf("sem initialize failed /n");
exit(1);
}
for(i=0;i
3. 分析信号量设置不合理,会出现什么情况。例如,什么时候会出现无法唤醒一个生产者(或消费者)的情况。
信号量设置不合理会使生产者(或消费者)进入永久堵塞状态。两个p原语调换顺序时即p(mutex)在前,p(empty)在后时会产生永久阻塞状态。这时生产者等着v(mutex),消费者等着v(full),所以进入死锁。
4. 举例说明在现实生活中符合“生产者-消费者模型”的五种情况。
买票,买保险,吃饭,取快递,取钱。