经典同步问题linux下的C实现:生产者-消费者问题,读者-写者问题,哲学家问题代码解析

原文网址https://blog.csdn.net/life_hunter/article/details/8790553,本文是对原文的说明
1.生产者-消费者问题

1) sem.c 实现了生产者和消费者的同步。
当生产者多于消费者的时候,产品最多可以达到8个。不会冒。
当消费者多于生产者的时候,产品最少不会少于0个,不会负值。
实现同步。注意这个例子是total_num从3减到1,才开始加的,1+7=8.所以最多到8.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>
#define msleep(x) usleep(x*1000)
#define PRODUCT_SPEED  3 
#define CONSUM_SPEED 1
#define INIT_NUM 3
#define TOTAL_NUM 10
 
sem_t p_sem,c_sem,sh_sem;
int num=INIT_NUM;
 
void product (void)
{
sleep (PRODUCT_SPEED);
}
 
 
int add_to_lib ()
{
num++;
msleep(500);
return num;
}
 
void consum()
{
sleep(CONSUM_SPEED);
} 
 
int sub_from_lib ()
{
num--;
msleep(500);
return num;
}
 
void *productor(void *arg)
{
while (1)
{
sem_wait(&p_sem);
product();
sem_wait(&sh_sem);
printf("push into!total_num=%d\n",add_to_lib());
sem_post(&sh_sem);
sem_post(&c_sem);
}
}
 
 
void *consumer (void *arg)
{
while (1)
{
sem_wait(&c_sem);
sem_wait(&sh_sem);
printf("pop out!total_num=%d\n",sub_from_lib());
sem_post(&sh_sem);
sem_post(&p_sem);
consum();
}
}
 
int main  ()
{
pthread_t tid1,tid2, tid3,tid4;
//10-3=7
sem_init(&p_sem,0,TOTAL_NUM-INIT_NUM);
//3
sem_init(&c_sem,0,INIT_NUM);
sem_init(&sh_sem,0,1);

pthread_create(&tid1,NULL,productor,NULL);
pthread_create(&tid3,NULL,productor,NULL);
pthread_create(&tid4,NULL,productor,NULL);
pthread_create(&tid2,NULL,consumer,NULL);
 
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return 0;
}

2) sem1.c和sem.c一样。
只是将同步的 sem_wait(&sh_sem);换成了pthread_mutex_lock(&mutex);

注意:其empty init is 5


#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <semaphore.h>  
#include <pthread.h>  
  
#define N 2   
#define N1 3   
#define N2 1   
#define M 10  
int in =0 ;  
int out =0 ;  
int buff[M]={0};  
  
sem_t empty_sem;  
sem_t full_sem;  
  
pthread_mutex_t mutex;  
int product_id = 0;  
int prochase_id = 0;  
  
void print()  
{  
int i;  
for (i=0;i<M;i++)  
printf("%d",buff[i]);  
printf("\n");  
}
  
void *product()  
{  
int id= ++product_id;  
  
while (1)   
{  
sleep (1);  
sem_wait(&empty_sem);  
pthread_mutex_lock(&mutex);  
  
in = in %M;  
printf("product %d in %d.like:\t",id,in);  
buff[in]=1;  
print();  
++in;  
  
pthread_mutex_unlock(&mutex);  
sem_post(&full_sem);  
}  
}  
  
void *prochase ()  
{  
int id=++prochase_id;  
while(1)   
{  
sleep(1);  
sem_wait(&full_sem);  
pthread_mutex_lock(&mutex);  
  
out = out % M;  
printf("prochase %d in %d.like: \t",id,out);  
  
buff[out]=0;  
print();  
++out;  
  
pthread_mutex_unlock(&mutex);  
sem_post(&empty_sem);  
}  
}  
  
int main ()  
{  
pthread_t id1[10];  
pthread_t id2[10];  
int i;  
int ret[10];  
   
int ini1=sem_init(&empty_sem,0,M-5);  
int ini2=sem_init(&full_sem,0,0);  
  
if (ini1 && ini2 !=0)  
{  
printf("sem init failed\n");  
exit(1);  
}  
  
int ini3=pthread_mutex_init(&mutex,NULL);  
if (ini3!=0)  
{  
printf("mutex init failed \n");  
exit (1);  
}  
  
for (i=0;i<N1;i++)  
{  
ret[i]=pthread_create(&id1[i],NULL,product,NULL);  
if (ret[i]!=0)  
{  
printf("product %d creation failed\n",i);  
exit(1);  
}  
}  
 
for (i=0;i<N2;i++)  
{  
ret[i]=pthread_create(&id2[i],NULL,prochase,NULL);  
if (ret[i]!=0)  
{  
printf("prochase %d creation failed\n",i);  
exit(1);  
}  
  
}  
  
for ( i=0;i<N;i++)  
{  
pthread_join(id1[i],NULL);  
pthread_join(id2[i],NULL);  
}  
exit(0);  
} 

3) [cpp] view plaincopy

 
  1. /*=============================================================== 
  2.  
  3.  * File Name : producerConsumerProblem.c 
  4.  * Creation Date : 2013-04-11 
  5.  * Last Modified : 2013年04月11日 星期四 20时53分13秒 
  6.  * Purpose :test linux semaphore usage 
  7.  
  8. ================================================================*/  
  9. #include <stdio.h>  
  10. #include <sys/types.h>  
  11. #include <semaphore.h>  
  12. #include <pthread.h>  
  13. #include <stdlib.h>  
  14.   
  15. void *producer_handler(void *ptr);  
  16. void *consumer_handler(void *ptr);  
  17.   
  18. sem_t mutex,blank,fill;  
  19. int *buffer;  
  20. int in=0,out=0,buffer_size=10;  
  21.   
  22. void main()  
  23. {  
  24.     if((buffer=(int *)malloc(buffer_size*sizeof(int)))==NULL)  
  25.         printf("can't allocate memroy on heap\n");  
  26.     sem_init(&mutex,0,1);  
  27.     sem_init(&blank,0,buffer_size);  
  28.     sem_init(&fill,0,0);  
  29.   
  30.     int err;  
  31.     pthread_t producer,consumer;  
  32.     err=pthread_create(&producer,NULL,producer_handler,NULL);  
  33.     if(err!=0)  
  34.         err_quit("can't create thread: %s\n",strerror(err));  
  35.     err=pthread_create(&consumer,NULL,consumer_handler,NULL);  
  36.     if(err!=0)  
  37.         err_quit("can't create thread: %s\n",strerror(err));  
  38.   
  39.     sleep(10);  
  40.   
  41. }  
  42.   
  43. void *producer_handler(void *ptr)  
  44. {  
  45.     while(1){  
  46.         static int data=0;  
  47.         sem_wait(&blank);  
  48.     //  sem_wait(&mutex);  
  49.       
  50.         buffer[in]=++data;  
  51.         printf("%d has been input to the buffer\n",data);  
  52.         in=(in+1+buffer_size)%buffer_size;  
  53.     //  sem_post(&mutex);  
  54.         sem_post(&fill);  
  55.         sleep(1);  
  56.     }  
  57.     return ((void *)0);  
  58. }  
  59.   
  60. void *consumer_handler(void *ptr)  
  61. {  
  62.     while(1){  
  63.         int fetch;  
  64.         sem_wait(&fill);  
  65.     //  sem_wait(&mutex);  
  66.         fetch=buffer[out];  
  67.         out=(out+1+buffer_size)%buffer_size;  
  68.         printf("%d has been fetched\n",fetch);  
  69.     //  sem_post(&mutex);  
  70.         sem_post(&blank);  
  71.         sleep(2);  
  72.     }  
  73.     return ((void *)0);  
  74. }  


2.读者-写者问题

1)  题目大意如下:有一个写者很多读者,多个读者可以同时读文件,但写者在写文件时不允许有读者在读文件,同样有读者读时写者也不能写。
当有读者的时候,readCount!=0,所以不能写。
当写的时候。readCount==0,同时pthread_mutex_lock(&wr);
所以无法读,因为第一个读者,要检测是不是在写。
每个读,局部变量,控制每个读的结束。
实现了读写同步,读读并行。


#include <pthread.h>
#include <signal.h>
#define N 5
#define M 10
 
pthread_mutex_t rd = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t wr = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t priority = PTHREAD_MUTEX_INITIALIZER;
 
int readCount = 0;
 
void* reader(void *arg)
{
int n = M;
int id = (int)arg;
while (n--) 
{
sleep(rand()%3);
pthread_mutex_lock(&priority);
pthread_mutex_lock(&rd);
readCount++;
if ( readCount ==1)
{
pthread_mutex_lock(&wr);
}
pthread_mutex_unlock(&rd);
pthread_mutex_unlock(&priority);
 
printf("reader %d is reading \n",id);
sleep(rand()%3);
 
pthread_mutex_lock(&rd);
readCount--;
if (readCount==0)
{
pthread_mutex_unlock(&wr);
}
pthread_mutex_unlock(&rd);
printf("reader %d is leaving \n",id);
}
printf("----reader %d has done----\n",(int)arg);
 
}
 
void* writer(void *arg)
{
int n = M;
while (n--)
{
sleep (rand()%4);
pthread_mutex_lock(&priority);
pthread_mutex_lock(&wr);
printf("\twriter is writing \n");
sleep (rand()%4);
pthread_mutex_unlock(&priority);
pthread_mutex_unlock(&wr);
printf("\twriter is leaving \n");
}
printf("----writer has done ----\n");
}
 
int main (int argc ,const char *asrgv[])
{
int err;
pthread_t tid[N],writer_tid;
int i;
 
for (i=0;i<N;i++)
{
err=pthread_create(&tid[i],NULL,reader,(void *)(i+1));
if (err !=0) {
printf("can;t create process for reader");
}
}
err = pthread_create(&writer_tid,NULL,writer,(void *)NULL);
if (err!=0)
{
printf("can;t cretee process for writer\n");
}
pause ();
return 0;
}

2)

  1. /*=============================================================== 
  2.  
  3.  * File Name : readerWriterProblem.c 
  4.  * Creation Date : 2013-04-11 
  5.  * Last Modified : 2013年04月11日 星期四 22时42分45秒 
  6.  * Purpose : 
  7.  
  8. ================================================================*/  
  9.   
  10. #include <stdio.h>  
  11. #include <sys/types.h>  
  12. #include <semaphore.h>  
  13. #include <pthread.h>  
  14. #include <stdlib.h>  
  15.   
  16. #define READER_NUM 5  
  17. void *reader_handler(void *ptr);  
  18. void *writer_handler(void *ptr);  
  19.   
  20. sem_t write_mutex;  
  21. sem_t mutex;  
  22. int read_count;  
  23.   
  24. void main()  
  25. {  
  26.     sem_init(&write_mutex,0,1);  
  27.     sem_init(&mutex,0,1);  
  28.     read_count=0;  
  29.       
  30.     int err,i;  
  31.     pthread_t reader[READER_NUM],writer;  
  32.     int args[READER_NUM];  
  33.     for(i=0;i<READER_NUM;++i){  
  34.         args[i]=i;  
  35.         err=pthread_create(&reader[i],NULL,reader_handler,(void*)&args[i]);  
  36.         if(err!=0)  
  37.             err_quit("can't create thread: %s\n",strerror(err));  
  38.     }  
  39.     err=pthread_create(&writer,NULL,writer_handler,NULL);  
  40.     if(err!=0)  
  41.         err_quit("can't create thread: %s\n",strerror(err));  
  42.   
  43.     sleep(10);  
  44.   
  45. }  
  46.   
  47. void *reader_handler(void *ptr)  
  48. {  
  49.     while(1){  
  50.         if(read_count==0){  
  51.             sem_wait(&write_mutex);  
  52.         }  
  53.         sem_wait(&mutex);  
  54.         ++read_count;  
  55.         sem_post(&mutex);  
  56.   
  57.         printf("There are %d readers reading\n",read_count);  
  58.         sleep(1);  
  59.   
  60.         sem_wait(&mutex);  
  61.         --read_count;  
  62.         sem_post(&mutex);  
  63.   
  64.         if(read_count==0){  
  65.             sem_post(&write_mutex);  
  66.         }  
  67.         sleep(1);  
  68.     }  
  69.     return ((void *)0);  
  70. }  
  71.   
  72. void *writer_handler(void *ptr)  
  73. {  
  74.     while(1){  
  75.         if(read_count==0){  
  76.             sem_wait(&write_mutex);  
  77.             printf("Writer writes\n");  
  78.             sem_post(&write_mutex);  
  79.         }  
  80.         else  
  81.             printf("Writer failed\n");  
  82.         sleep(1);  
  83.     }  
  84.     return ((void *)0);  
  85. }  

3.哲学家进餐问题

有一点要注意: 就是循环生生成线程时,要给线程处理函数传入计数器参数时,不能直接用计数器的地址——因为计数器会现在主函数中改变。显然也不能用循环中的临时变量来记录。所以只好再有外部数组来记录这些实参值了。

[cpp]  view plain copy
 
  1. /*=============================================================== 
  2.  
  3.  * File Name : dinningPhilosophersProblem.c 
  4.  * Creation Date : 2013-04-11 
  5.  * Last Modified : 2013年04月11日 星期四 21时34分18秒 
  6.  * Purpose : 
  7.  
  8. ================================================================*/  
  9.   
  10. #include <stdio.h>  
  11. #include <sys/types.h>  
  12. #include <semaphore.h>  
  13. #include <pthread.h>  
  14. #include <stdlib.h>  
  15.   
  16. #define PHILO_NUM 5  
  17. void *philosopher(void *arg);  
  18.   
  19. sem_t sema[PHILO_NUM];  
  20. sem_t mutex;  
  21. void main()  
  22. {  
  23.     int i,err;  
  24.     int args[PHILO_NUM];  
  25.     for(i=0;i<PHILO_NUM;++i){  
  26.         sem_init(sema+i,0,1);  
  27.         args[i]=i;  
  28.     }    
  29.     sem_init(&mutex,0,1);  
  30.     pthread_t philosophers[PHILO_NUM];  
  31.     for(i=0;i<PHILO_NUM;++i){  
  32.         err=pthread_create(philosophers+i,NULL,philosopher,(void*)&args[i]);  
  33.         if(err!=0)  
  34.             err_quit("can't create thread: %s\n",strerror(err));  
  35.     }  
  36.     sleep(5);  
  37. }  
  38.   
  39. void *philosopher(void *arg)  
  40. {  
  41.     int num;  
  42.     num=*((int *)arg);  
  43.     //printf("Philosopher %d eats\n",num);  
  44.     while(1){  
  45.         sem_wait(&mutex);   
  46.         sem_wait(&sema[num]);  
  47.         sem_wait(&sema[(num+1)%PHILO_NUM]);  
  48.         sem_post(&mutex);  
  49.         printf("Philosopher %d eats\n",num);  
  50.         sem_post(&sema[num]);  
  51.         sem_post(&(sema[(num+1)%PHILO_NUM]));  
  52.         sleep(1);  
  53.     }  
  54.   
  55.     return ((void *)0);  
  56. }  

 

 

哲学家问题解决:
comments:5个人5副刀叉。4个人吃饭毕竟不向5个人,肯定至少有一个会吃到,然后放下,然后其他的人就不会一直hold,所以让其中之一先sleep一下。即不会死锁。
但是从理论上讲,只是开始的时候,4人同吃,不会出现死锁。
但是过了id=0,sleep之后,又变成5个人同吃。还是可能存在死锁的可能。

#include <pthread.h>  
#include <stdio.h>  
#include <unistd.h>  
#include <stdlib.h>  
#include <errno.h>  
#include <assert.h>  
  
#define PHILOS 5  
#define DELAY 5000  
#define FOOD 50  
  
void *philosopher (void *id);  
void grab_chopstick(int ,  
    int ,  
   char *);  
void down_chopsticks (int ,  
int);  
int food_on_table();  
  
pthread_mutex_t chopstick[PHILOS];  
pthread_t philo[PHILOS];  
pthread_mutex_t food_lock;  
int sleep_seconds=10;  
  
int main (int argn,char **argv)  
{  
int i;  
if (argn==2)  
sleep_seconds=atoi(argv[1]);  
pthread_mutex_init(&food_lock,NULL);  
for (i=0;i<PHILOS;i++)  
pthread_mutex_init(&chopstick[i],NULL);  
for (i=0;i<PHILOS;i++)  
pthread_create(&philo[i],NULL,philosopher,(void*)i);  
for (i=0;i<PHILOS;i++)  
pthread_join(philo[i],NULL);  
return 0;  
}  
  
void *  
philosopher (void *num)  
{  
int id;  
int i,left_chopstick,right_chopstick,f;  
  
id=(int)num;  
printf("Philosopher %d is done thinking and now ready to eat\n ",id);  
right_chopstick=id;  
left_chopstick=id+1;  
//wrap around the chopsticks  
if (left_chopstick==PHILOS)  
left_chopstick=0;  
while (f=food_on_table()) {  
/*thanks to philosophers#1 who would like to take a nap  
*before picking up the chopsticks,the other philosophers   
*may be able to eat their dishes and not deadlock  
*/  
if (id==0)  
sleep(sleep_seconds);  
grab_chopstick(id,right_chopstick,"right");  
usleep(DELAY *(FOOD -f +1));  
grab_chopstick(id,left_chopstick,"left");  
  
printf("Philosopher %d:eating\n",id);  
usleep(DELAY *(FOOD -f +1));  
down_chopsticks(left_chopstick,right_chopstick);  
}  
printf("Philosopher %d is done eating \n",id);  
return (NULL);  
}  
  
  
int food_on_table ()  
{  
static int food=FOOD;  
int myfood;  
  
pthread_mutex_lock(&food_lock);  
if(food>0) {  
food--;  
}  
myfood=food;  
pthread_mutex_unlock(&food_lock);  
return myfood;  
}  
  
  
void grab_chopstick(int phi1,  
  int c,  
   

 

 

 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值