哲学家吃饭问题---进程互斥与同步

目录

实验二 消费者生产者模型

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.1实验目的

1. 熟悉进程的九种状态,理解并发进程临界资源,互斥和同步资源的差异。

2. 理解掌握P(S)原语和V(S)原语的操作原理,以及信号量S的意义。

3. 理解经典“生产者-消费者”问题。

4. 掌握线程编程解决互斥和同步资源的方法。

 

1.2实验内容

 

1. 设计编写“生产者-消费者”的程序,运行并记录结果。

2. 随机定义生产者进程和消费者进程并发的数量和次序,分析信号量的变化过程,以及线程状态变化过程。

3. 分析信号量设置不合理,会出现什么情况。例如,什么时候会出现无法唤醒一个生产者(或消费者)的情况。

4. 举例说明在现实生活中符合“生产者-消费者模型”的五种情况。

 

1.3基本概念与原理

生产者-消费者(producer-consumer)问题是一个经典的进程同步问题,最早由Dijkstra提出,用以演示他提出的信号量机制。生产者-消费者也称作有界缓冲区(bounded-buffer)问题,两个进程共享一个公共的固定大小的缓冲区。其中一个是生产者,用于将消息放入缓冲区;另外一个是消费者,用于从缓冲区中取出消息。问题出现在当缓冲区已经满了,而此时生产者还想向其中放入一个新的数据项的情形,其解决方法是让生产者此时进行休眠,等待消费者从缓冲区中取走了一个或者多个数据后再去唤醒它。同样地,当缓冲区已经空了,而消费者还想去取消息,此时也可以让消费者进行休眠,等待生产者放入一个或者多个数据时再唤醒它。

 

 

 

1.31 程序设计思想

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.32程序结构

(1)生产者

哲学家吃饭问题---进程互斥与同步_第1张图片

生产者 图 1

 

 

 

(2)消费者

哲学家吃饭问题---进程互斥与同步_第2张图片

消费者 图 2

 

 

1.33算法程序


#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

 

 

 

1.34程序运行图

哲学家吃饭问题---进程互斥与同步_第3张图片

 

 

3. 分析信号量设置不合理,会出现什么情况。例如,什么时候会出现无法唤醒一个生产者(或消费者)的情况。

信号量设置不合理会使生产者(或消费者)进入永久堵塞状态。两个p原语调换顺序时即p(mutex)在前,p(empty)在后时会产生永久阻塞状态。这时生产者等着v(mutex),消费者等着v(full),所以进入死锁。

4. 举例说明在现实生活中符合“生产者-消费者模型”的五种情况。

买票,买保险,吃饭,取快递,取钱。

 

你可能感兴趣的:(操作系统实验)