生产者,消费者问题

互斥锁实现:

“生产者/消费者”问题描述:

有一个有限缓冲区和两个线程:生产者和消费者。他们分别把产品放入缓冲区和从缓冲区中拿走产品。当一个生产者在缓冲区满时必须等待,当一个消费者在缓冲区空时也必须等待。


1.      单锁模型


  1. #include”stdio.h”  
  2. #include”pthread.h”  
  3.   
  4. int buffer[10];  
  5. int top = 0;  
  6. int itime = 0;  
  7. int itime2 = 0;  
  8.   
  9. pthread_t thread[2];  
  10. pthread_mutex_t mut;  
  11.   
  12. void producer()  
  13. {  
  14.     while(1)  
  15.     {  
  16.         if(itime == 10) return;  
  17.         pthread_mutex_lock(&mut);  
  18.         if(top == 10)  
  19.         {  
  20.             printf(”buffer is full…producer is waiting…\n”);  
  21.             pthread_mutex_unlock(&mut);  
  22.             continue;  
  23.         }  
  24.         printf(”pruducter set the %d\n”, itime);  
  25.         top++;  
  26.         itime++;  
  27.         pthread_mutex_unlock(&mut);  
  28.     }  
  29. }  
  30.   
  31.   
  32. void consumer()  
  33. {  
  34.     while(1)  
  35.     {  
  36.         if(itime2 == 10) return;  
  37.         pthread_mutex_lock(&mut);  
  38.         if(top == 0)  
  39.         {  
  40.             printf(”buffer is empty…consumer is waiting…\n”);  
  41.             pthread_mutex_unlock(&mut);  
  42.             continue;  
  43.         }  
  44.         printf(”consumer get the %d\n”, itime2);  
  45.         top–;  
  46.         itime2++;  
  47.         pthread_mutex_unlock(&mut);  
  48.     }  
  49. }  
  50.   
  51. int main()  
  52. {  
  53.     pthread_create(&thread[0], NULL, (void*)(&producer), NULL);   
  54.     pthread_create(&thread[1], NULL, (void*)(&consumer), NULL);   
  55.       
  56.     sleep(1);  
  57.     return 0;  
  58. }  
#include"stdio.h"




#include"pthread.h" int buffer[10]; int top = 0; int itime = 0; int itime2 = 0; pthread_t thread[2]; pthread_mutex_t mut; void producer() { while(1) { if(itime == 10) return; pthread_mutex_lock(&mut); if(top == 10) { printf("buffer is full...producer is waiting...\n"); pthread_mutex_unlock(&mut); continue; } printf("pruducter set the %d\n", itime); top++; itime++; pthread_mutex_unlock(&mut); } } void consumer() { while(1) { if(itime2 == 10) return; pthread_mutex_lock(&mut); if(top == 0) { printf("buffer is empty...consumer is waiting...\n"); pthread_mutex_unlock(&mut); continue; } printf("consumer get the %d\n", itime2); top--; itime2++; pthread_mutex_unlock(&mut); } } int main() { pthread_create(&thread[0], NULL, (void*)(&producer), NULL); pthread_create(&thread[1], NULL, (void*)(&consumer), NULL); sleep(1); return 0; }

运行结果

  1. buffer is empty…consumer is waiting…  
  2. buffer is empty…consumer is waiting…  
  3. buffer is empty…consumer is waiting…  
  4. pruducter set the 0  
  5. pruducter set the 1  
  6. pruducter set the 2  
  7. pruducter set the 3  
  8. pruducter set the 4  
  9. pruducter set the 5  
  10. pruducter set the 6  
  11. pruducter set the 7  
  12. pruducter set the 8  
  13. pruducter set the 9  
  14. consumer get the 0  
  15. consumer get the 1  
  16. consumer get the 2  
  17. consumer get the 3  
  18. consumer get the 4  
  19. consumer get the 5  
  20. consumer get the 6  
  21. consumer get the 7  
  22. consumer get the 8  
  23. consumer get the 9  
buffer is empty...consumer is waiting...
buffer is empty...consumer is waiting...
buffer is empty...consumer is waiting...
pruducter set the 0
pruducter set the 1
pruducter set the 2
pruducter set the 3
pruducter set the 4
pruducter set the 5
pruducter set the 6
pruducter set the 7
pruducter set the 8
pruducter set the 9
consumer get the 0
consumer get the 1
consumer get the 2
consumer get the 3
consumer get the 4
consumer get the 5
consumer get the 6
consumer get the 7
consumer get the 8
consumer get the 9

分析

容易出现极端状况,一开始一直是consumer加锁,producer无法提供;不久后producer终于得到加锁,存入了10个货物,而后consumer取得10个货物。


 2. 两个互斥锁



  1. #include”stdio.h”  
  2. #include”pthread.h”  
  3.   
  4. int buffer[10];  
  5. int top = 0;  
  6. int itime = 0;  
  7. int itime2 = 0;  
  8.   
  9. pthread_t thread[2];  
  10. pthread_mutex_t mut;  
  11. pthread_mutex_t mut2;  
  12.   
  13. void producer()  
  14. {  
  15.     while(1)  
  16.     {  
  17.         if(itime == 10) return;  
  18.         pthread_mutex_lock(&mut);  
  19.         if(top == 10)  
  20.         {  
  21.             printf(”buffer is full…producer is waiting…\n”);  
  22.             pthread_mutex_unlock(&mut2);  
  23.             continue;  
  24.         }  
  25.         printf(”pruducter set the %d\n”, itime);  
  26.         top++;  
  27.         itime++;  
  28.         pthread_mutex_unlock(&mut2);  
  29.     }  
  30. }  
  31.   
  32.   
  33. void consumer()  
  34. {  
  35.     while(1)  
  36.     {  
  37.         if(itime2 == 10) return;  
  38.         pthread_mutex_lock(&mut2);  
  39.         if(top == 0)  
  40.         {  
  41.             printf(”buffer is empty…consumer is waiting…\n”);  
  42.             pthread_mutex_unlock(&mut);  
  43.             continue;  
  44.         }  
  45.         printf(”consumer get the %d\n”, itime2);  
  46.         top–;  
  47.         itime2++;  
  48.         pthread_mutex_unlock(&mut);  
  49.     }  
  50. }  
  51.   
  52. int main()  
  53. {  
  54.     pthread_create(&thread[0], NULL, (void*)(&producer), NULL);   
  55.     pthread_create(&thread[1], NULL, (void*)(&consumer), NULL);   
  56.       
  57.     sleep(1);  
  58.     return 0;  
  59. }  
#include"stdio.h"




#include"pthread.h" int buffer[10]; int top = 0; int itime = 0; int itime2 = 0; pthread_t thread[2]; pthread_mutex_t mut; pthread_mutex_t mut2; void producer() { while(1) { if(itime == 10) return; pthread_mutex_lock(&mut); if(top == 10) { printf("buffer is full...producer is waiting...\n"); pthread_mutex_unlock(&mut2); continue; } printf("pruducter set the %d\n", itime); top++; itime++; pthread_mutex_unlock(&mut2); } } void consumer() { while(1) { if(itime2 == 10) return; pthread_mutex_lock(&mut2); if(top == 0) { printf("buffer is empty...consumer is waiting...\n"); pthread_mutex_unlock(&mut); continue; } printf("consumer get the %d\n", itime2); top--; itime2++; pthread_mutex_unlock(&mut); } } int main() { pthread_create(&thread[0], NULL, (void*)(&producer), NULL); pthread_create(&thread[1], NULL, (void*)(&consumer), NULL); sleep(1); return 0; }
运行结果

  1. buffer is empty…consumer is waiting…  
  2. pruducter set the 0  
  3. consumer get the 0  
  4. pruducter set the 1  
  5. consumer get the 1  
  6. pruducter set the 2  
  7. consumer get the 2  
  8. pruducter set the 3  
  9. consumer get the 3  
  10. pruducter set the 4  
  11. consumer get the 4  
  12. pruducter set the 5  
  13. consumer get the 5  
  14. pruducter set the 6  
  15. consumer get the 6  
  16. pruducter set the 7  
  17. consumer get the 7  
  18. pruducter set the 8  
  19. consumer get the 8  
  20. pruducter set the 9  
  21. consumer get the 9  
buffer is empty...consumer is waiting...
pruducter set the 0
consumer get the 0
pruducter set the 1
consumer get the 1
pruducter set the 2
consumer get the 2
pruducter set the 3
consumer get the 3
pruducter set the 4
consumer get the 4
pruducter set the 5
consumer get the 5
pruducter set the 6
consumer get the 6
pruducter set the 7
consumer get the 7
pruducter set the 8
consumer get the 8
pruducter set the 9
consumer get the 9

很完美对不对?生产者生产一个就把自己锁起来,消费者消费一个后解锁生产者,把自己锁起来,生产者继续生产,循环反复。互斥锁的确能很好的实现进程/线程之间的同步问题,但是它是通过锁机制来实现的,就是仅仅通过加锁和解锁实现同步,效率比较低。


3. 利用条件变量

  1. #include”stdio.h”  
  2. #include”pthread.h”  
  3.   
  4. int buffer[10];  
  5. int top = 0;  
  6. int itime = 0;  
  7. int itime2 = 0;  
  8.   
  9. pthread_t thread[2];  
  10. pthread_mutex_t mut;  
  11. pthread_cond_t con, con2;  
  12.   
  13. void producer()  
  14. {  
  15.     while(1)  
  16.     {  
  17.         if(itime == 10) return;  
  18.         pthread_mutex_lock(&mut);  
  19.         if(top == 10)  
  20.         {  
  21.             printf(”buffer is full…producer is waiting…\n”);  
  22.             pthread_cond_wait(&con, &mut);  
  23.         }  
  24.         printf(”pruducter set the %d\n”, itime);  
  25.         top++;  
  26.         itime++;  
  27.         pthread_cond_signal(&con2);  
  28.         pthread_mutex_unlock(&mut);  
  29.         sleep(1);  
  30.     }  
  31. }  
  32.   
  33.   
  34. void consumer()  
  35. {  
  36.     while(1)  
  37.     {  
  38.         if(itime2 == 10) return;  
  39.         pthread_mutex_lock(&mut);  
  40.         if(top == 0)  
  41.         {  
  42.             printf(”buffer is empty…consumer is waiting…\n”);  
  43.             pthread_cond_wait(&con2, &mut);  
  44.         }  
  45.         printf(”consumer get the %d\n”, itime2);  
  46.         top–;  
  47.         itime2++;  
  48.         pthread_cond_signal(&con);  
  49.         pthread_mutex_unlock(&mut);  
  50.         sleep(1);  
  51.     }  
  52. }  
  53.   
  54. int main()  
  55. {  
  56.     pthread_create(&thread[0], NULL, (void*)(&producer), NULL);   
  57.     pthread_create(&thread[1], NULL, (void*)(&consumer), NULL);   
  58.       
  59.     sleep(10);  
  60.     return 0;  
  61. }  
#include"stdio.h"




#include"pthread.h" int buffer[10]; int top = 0; int itime = 0; int itime2 = 0; pthread_t thread[2]; pthread_mutex_t mut; pthread_cond_t con, con2; void producer() { while(1) { if(itime == 10) return; pthread_mutex_lock(&mut); if(top == 10) { printf("buffer is full...producer is waiting...\n"); pthread_cond_wait(&con, &mut); } printf("pruducter set the %d\n", itime); top++; itime++; pthread_cond_signal(&con2); pthread_mutex_unlock(&mut); sleep(1); } } void consumer() { while(1) { if(itime2 == 10) return; pthread_mutex_lock(&mut); if(top == 0) { printf("buffer is empty...consumer is waiting...\n"); pthread_cond_wait(&con2, &mut); } printf("consumer get the %d\n", itime2); top--; itime2++; pthread_cond_signal(&con); pthread_mutex_unlock(&mut); sleep(1); } } int main() { pthread_create(&thread[0], NULL, (void*)(&producer), NULL); pthread_create(&thread[1], NULL, (void*)(&consumer), NULL); sleep(10); return 0; }

运行结果

  1. buffer is empty…consumer is waiting…  
  2. pruducter set the 0  
  3. consumer get the 0  
  4. buffer is empty…consumer is waiting…  
  5. pruducter set the 1  
  6. consumer get the 1  
  7. buffer is empty…consumer is waiting…  
  8. pruducter set the 2  
  9. consumer get the 2  
  10. buffer is empty…consumer is waiting…  
  11. pruducter set the 3  
  12. consumer get the 3  
  13. pruducter set the 4  
  14. consumer get the 4  
  15. pruducter set the 5  
  16. consumer get the 5  
  17. pruducter set the 6  
  18. consumer get the 6  
  19. pruducter set the 7  
  20. consumer get the 7  
  21. pruducter set the 8  
  22. consumer get the 8  
  23. pruducter set the 9  
  24. consumer get the 9  
buffer is empty...consumer is waiting...
pruducter set the 0
consumer get the 0
buffer is empty...consumer is waiting...
pruducter set the 1
consumer get the 1
buffer is empty...consumer is waiting...
pruducter set the 2
consumer get the 2
buffer is empty...consumer is waiting...
pruducter set the 3
consumer get the 3
pruducter set the 4
consumer get the 4
pruducter set the 5
consumer get the 5
pruducter set the 6
consumer get the 6
pruducter set the 7
consumer get the 7
pruducter set the 8
consumer get the 8
pruducter set the 9
consumer get the 9


结果还算比较正常,理解一下变量的使用。消费者发现缓冲区没有东西,通过条件变量把自己锁住;生产者生产并激活消费者;消费者从缓冲区消费;当生产者发现缓冲区满的时候,通过条件变量把自己锁住,消费者消费并重新激活生产者。如此。


信号量实现

 文章出自: http://page.renren.com/600235506/note/492983524

学习了信号量以及共享内存后,我们就可以实现进程的同步与互斥了。说到这里,最经典的例子莫过于生产者和消费者模型。下面就和大家一起分析,如何一步步实现这个经典模型。

下面程序,实现的是多个生产者和多个消费者对N个缓冲区(N个货架)进行访问的例子。现在先想想我们以前的伪代码是怎么写的?是不是这样:

//生产者:

  1. while(1)  
  2. {  
  3.     p(semid,1);  
  4.     sleep(3);  
  5.     p(semid,0);  
  6.     //producer is producing a product  
  7.     goods=rand()%10;  
  8.     shmaddr[indexaddr[0]]=goods;  
  9.     printf(”producer:%d produces a product[%d]:%d\n”,getpid(),indexaddr[0],goods);  
  10.     indexaddr[0]=(indexaddr[0]+1)%10;  
  11.     v(semid,0);  
  12.     sleep(3);  
  13.     v(semid,2);  
  14. }  
  while(1)
    {
        p(semid,1);
        sleep(3);
        p(semid,0);
        //producer is producing a product
        goods=rand()%10;
        shmaddr[indexaddr[0]]=goods;
        printf("producer:%d produces a product[%d]:%d\n",getpid(),indexaddr[0],goods);
        indexaddr[0]=(indexaddr[0]+1)%10;
        v(semid,0);
        sleep(3);
        v(semid,2);
    }

//消费者:

  1. while(1)  
  2. {  
  3.     p(semid,2);  
  4.     sleep(1);  
  5.     p(semid,0);  
  6.     //consumer is consuming a product  
  7.     goods=shmaddr[indexaddr[1]];  
  8.     printf(”consumer:%d consumes a product[%d]:%d\n”,getpid(),indexaddr[1],goods);  
  9.     indexaddr[1]=(indexaddr[1]+1)%num;  
  10.     v(semid,0);  
  11.     sleep(1);  
  12.     v(semid,1);  
  13. }  
   while(1)
    {
        p(semid,2);
        sleep(1);
        p(semid,0);
        //consumer is consuming a product
        goods=shmaddr[indexaddr[1]];
        printf("consumer:%d consumes a product[%d]:%d\n",getpid(),indexaddr[1],goods);
        indexaddr[1]=(indexaddr[1]+1)%num;
        v(semid,0);
        sleep(1);
        v(semid,1);
    }


 

可能上面的代码你有些眼熟,又有些困惑,因为它和课本上的代码不完全一样,其实上面的代码就是伪代码的linuxC语言具体实现。我们从上面的代码中慢慢寻找伪代码的踪迹:p(semid,0)和v(semid,0)的作用是让进程互斥访问临界区。临界区中包含的数据indexaddr[0],indexaddr[1],以及shmaddr数组分别对应伪代码中的in,out,buffer。p(semid,1)和v(semid,2)以及p(semid,2)和v(semid,1)实现的是同步作用。

并且,在生产者中,生产者生产了一个货物(goods=rand()%10;),然后将这个货物放上货架(shmaddr[indexaddr[0]]=goods;)。在消费者中,消费和从货架上取下货物(goods=shmaddr[indexaddr[1]];)。

好了,现在再看一边上面的代码,我想你的思路就清晰了。

了解了核心代码,并不能算就完成了生产者和消费者模型,因为生产者和消费者核心代码前还得做一些些准备工作,具体要准备些什么,我们具体来分析。

首先申请一块共享内存,这块共享内存用于存放生产者所生产的货物。同时我们可以看到这块共享内存大小为10字节。这里需要注意,每个生产着或消费者运行后,都要去试着分配这样的一块共享内存。如果在当前进程运行前已经有某个进程已经创建了这块共享内存,那么这个进程就不再创建(此时createshm会返回-1并且错误代码为EEXIST),只是打开这块共享内存。创建后,再将这块共享内存添加到当前进程的地址空间。

  1. num=10;  
  2. //create a shared memory as goods buffer  
  3. if((shmid_goods=createshm(“.”,’s’,num))==-1)  
  4. {  
  5.     if(errno==EEXIST)  
  6.     {  
  7.         if((shmid_goods=openshm(“.”,’s’))==-1)  
  8.         {  
  9.             exit(1);  
  10.         }  
  11.     }  
  12.     else  
  13.     {  
  14.         perror(”create shared memory failed\n”);  
  15.             exit(1);  
  16.     }  
  17. }  
  18. //attach the shared memory to the current process  
  19. if((shmaddr=shmat(shmid_goods,(char*)0,0))==(char*)-1)  
  20. {  
  21.     perror(”attach shared memory error\n”);  
  22.     exit(1);  
  23. }  
 num=10;
    //create a shared memory as goods buffer
    if((shmid_goods=createshm(".",'s',num))==-1)
    {
        if(errno==EEXIST)
        {
            if((shmid_goods=openshm(".",'s'))==-1)
            {
                exit(1);
            }
        }
        else
        {
            perror("create shared memory failed\n");
                exit(1);
        }
    }
    //attach the shared memory to the current process
    if((shmaddr=shmat(shmid_goods,(char*)0,0))==(char*)-1)
    {
        perror("attach shared memory error\n");
        exit(1);
    }


 

接下来还要再申请一块共享内存,用于存放两个整形变量in和out(其实就是申请一个含有2个整形变量的数组而已)。他们记录的是生产和消费货物时“货架”的索引。与上面情况相同,如果已经有其他进程创建了此块共享内存,那么当前进程只是打开它而已。

注意这里对两个整形变量的初始化时的值均为0。

  1. //create a shared memory as index  
  2. if((shmid_index=createshm(“.”,‘z’,2))==-1)  
  3. {  
  4.     if(errno==EEXIST)  
  5.     {  
  6.         if((shmid_index=openshm(“.”,‘z’))==-1)  
  7.         {  
  8.             exit(1);  
  9.         }  
  10.     }  
  11.     else  
  12.     {  
  13.         perror(”create shared memory failed\n”);  
  14.             exit(1);  
  15.     }  
  16. }  
  17. else  
  18. {  
  19.     is_noexist=1;  
  20. }  
  21. //attach the shared memory to the current process  
  22. if((indexaddr=shmat(shmid_index,(int*)0,0))==(int*)-1)  
  23. {  
  24.     perror(”attach shared memory error\n”);  
  25.     exit(1);  
  26. }  
  27. if(is_noexist)  
  28. {  
  29.     indexaddr[0]=0;  
  30.     indexaddr[1]=0;  
  31. }  
  //create a shared memory as index
    if((shmid_index=createshm(".",'z',2))==-1)
    {
        if(errno==EEXIST)
        {
            if((shmid_index=openshm(".",'z'))==-1)
            {
                exit(1);
            }
        }
        else
        {
            perror("create shared memory failed\n");
                exit(1);
        }
    }
    else
    {
        is_noexist=1;
    }
    //attach the shared memory to the current process
    if((indexaddr=shmat(shmid_index,(int*)0,0))==(int*)-1)
    {
        perror("attach shared memory error\n");
        exit(1);
    }
    if(is_noexist)
    {
        indexaddr[0]=0;
        indexaddr[1]=0;
    }


 

接下来就是创建一个信号量集,这个信号量集中包含三个信号量。第一个信号量实现的互斥作用,即进程对临界区的互斥访问。剩下两个均实现的是同步作用,协调生产者和消费者的合理运行,即货架上没有空位时候生产者不再生产,货架上无商品时消费者不再消费。

注意下面对每个信号量的赋值情况。互斥信号量当然初值为1。而同步信号量两者之和不能大于num的值。

  1. //create a semaphore set including 3 semaphores  
  2. if((semid=createsem(“.”,‘t’,3,0))==-1)  
  3. {  
  4.     if(errno==EEXIST)  
  5.     {  
  6.         if((semid=opensem(“.”,‘t’))==-1)  
  7.         {  
  8.             exit(1);  
  9.         }  
  10.     }  
  11.     else  
  12.     {  
  13.         perror(”semget error:”);  
  14.         exit(1);  
  15.     }  
  16. }  
  17. else  
  18. {  
  19.     union semun arg;  
  20.         //seting value for mutex semaphore  
  21.             arg.val=1;  
  22.             if(semctl(semid,0,SETVAL,arg)==-1)  
  23.             {  
  24.         perror(”setting semaphore value failed\n”);  
  25.             return -1;  
  26.             }  
  27.             //set value for synchronous semaphore  
  28.         arg.val=num;  
  29.             //the num means that the producer can continue to produce num products  
  30.             if(semctl(semid,1,SETVAL,arg)==-1)  
  31.             {  
  32.         perror(”setting semaphore value failed\n”);  
  33.             return -1;  
  34.             }  
  35.             //the last semaphore’s value is default  
  36.             //the default value ‘0’ means that the consumer is not use any product now  
  37.    }  
   //create a semaphore set including 3 semaphores
    if((semid=createsem(".",'t',3,0))==-1)
    {
        if(errno==EEXIST)
        {
            if((semid=opensem(".",'t'))==-1)
            {
                exit(1);
            }
        }
        else
        {
            perror("semget error:");
            exit(1);
        }
    }
    else
    {
        union semun arg;
            //seting value for mutex semaphore
            arg.val=1;
            if(semctl(semid,0,SETVAL,arg)==-1)
            {
            perror("setting semaphore value failed\n");
                return -1;
                }
            //set value for synchronous semaphore
            arg.val=num;
                //the num means that the producer can continue to produce num products
            if(semctl(semid,1,SETVAL,arg)==-1)
                {
            perror("setting semaphore value failed\n");
                return -1;
            }
            //the last semaphore's value is default
            //the default value '0' means that the consumer is not use any product now
    }

基本上这样,就算完成了生产者和消费者的前期工作。我们可以看到,在核心代码中,我们只需要“装模作样”的将代码“各就各位”即可,当然这需要你理解生产者消费者这个基本模型。而在下面的准备代码中,则需要我们理解关于信号量和共享内存的一些基本函数。

最后再说说使用,建议先运行一个生产者和一个消费者,观察两者是如何协调工作的。然后再只运行一个生产者或一个消费者,看其是否会阻塞。了解了以上情况后,你就可以同时运行多个生产者和消费者了。

下面是源代码:

shm.h

  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <stdlib.h>  
  4. #include <unistd.h>  
  5. #include <sys/types.h>  
  6. #include <sys/ipc.h>  
  7. #include <sys/sem.h>  
  8. #include <sys/shm.h>  
  9. #include <errno.h>  
  10.   
  11. #define SHM_SIZE 1024     
  12.   
  13. union semun  
  14. {  
  15.     int val;  
  16.     struct semid_ds *buf;  
  17.     unsigned short *array;  
  18. };  
  19.   
  20. //create a semaphore set  
  21. int createsem(const char *pathname,int proj_id,int num,int init_val)  
  22. {  
  23.     key_t key;  
  24.     int i,semid;  
  25.     union semun arg;  
  26.   
  27.     if((key=ftok(pathname,proj_id))==-1)  
  28.     {  
  29.         perror(”ftok error:”);  
  30.         return -1;  
  31.     }  
  32.   
  33.     if((semid=semget(key,num,IPC_CREAT|IPC_EXCL|0666))==-1)  
  34.     {  
  35.         return -1;  
  36.     }  
  37.   
  38.     //initialize the value of semaphore  
  39.     arg.val=init_val;  
  40.     for(i=0;i<num;i++)  
  41.     {  
  42.         if(semctl(semid,i,SETVAL,arg)==-1)  
  43.         {  
  44.             perror(”semctl error:”);  
  45.             return -1;  
  46.         }  
  47.     }  
  48.   
  49.     return (semid);  
  50. }  
  51.   
  52. //open the semaphore set  
  53. int opensem(const char*pathname,int proj_id)  
  54. {  
  55.     key_t key;  
  56.     int semid;  
  57.   
  58.     if((key=ftok(pathname,proj_id))==-1)  
  59.     {  
  60.         perror(”ftok error:”);  
  61.         return -1;  
  62.     }  
  63.   
  64.     //just get the id of semaphore set  
  65.     if((semid=semget(key,0,IPC_CREAT|0666))==-1)  
  66.     {  
  67.         perror(”semget error:”);  
  68.         return -1;  
  69.     }  
  70.   
  71.     return (semid);  
  72. }  
  73.   
  74. //P operation  
  75. int p(int semid,int index)  
  76. {  
  77.     struct sembuf buf={0,-1,0};  
  78.   
  79.     if(index<0)  
  80.     {  
  81.         printf(”error:the index is invalid\n”);  
  82.         return -1;  
  83.     }  
  84.   
  85.     buf.sem_num=index;  
  86.     if(semop(semid,&buf,1)==-1)  
  87.     {  
  88.         perror(”semop error:”);  
  89.         return -1;  
  90.     }  
  91.   
  92.     return 1;  
  93.   
  94. }  
  95.   
  96. //V opeation  
  97. int v(int semid,int index)  
  98. {  
  99.     struct sembuf buf={0,+1,0};  
  100.   
  101.     if(index<0)  
  102.     {  
  103.         printf(”error:the index is invalid\n”);  
  104.         return -1;  
  105.     }  
  106.   
  107.     buf.sem_num=index;  
  108.     if(semop(semid,&buf,1)==-1)  
  109.     {  
  110.         perror(”semop error:”);  
  111.         return -1;  
  112.     }  
  113.   
  114.     return 1;  
  115. }  
  116.   
  117. //delete the semaphore set  
  118. int deletesem(int semid)  
  119. {  
  120.     return (semctl(semid,0,IPC_RMID,0)==-1);  
  121. }  
  122.   
  123. //waiting for the semaphore is equal to 1  
  124. int waitsem(int semid,int index)  
  125. {  
  126.     while(semctl(semid,index,GETVAL,0)==0)  
  127.     {  
  128.         sleep(1);  
  129.         printf(”I am waiting for semval equals 1..\n”);  
  130.     }  
  131.     return 1;  
  132. }  
  133.   
  134. //create share memory  
  135. int createshm(char *pathname,int proj_id,size_t size)  
  136. {  
  137.     key_t key;  
  138.     int shmid;  
  139.   
  140.     if((key=ftok(pathname,proj_id))==-1)  
  141.     {  
  142.         perror(”ftok error:”);  
  143.         return -1;  
  144.     }  
  145.   
  146.     if((shmid=shmget(key,size,IPC_CREAT|IPC_EXCL|0666))==-1)  
  147.     {  
  148.         return -1;  
  149.     }  
  150.   
  151.     return (shmid);  
  152. }  
  153. //open share memory  
  154. int openshm(char *pathname,int proj_id)  
  155. {  
  156.     key_t key;  
  157.     int shmid;  
  158.   
  159.     if((key=ftok(pathname,proj_id))==-1)  
  160.     {  
  161.         perror(”ftok error:”);  
  162.         return -1;  
  163.     }  
  164.   
  165.     if((shmid=shmget(key,0,IPC_CREAT|0666))==-1)  
  166.     {  
  167.         perror(”shmget error:”);  
  168.         return -1;  
  169.     }  
  170.   
  171.     return (shmid);  
  172. }  
#include <stdio.h>




#include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #include <errno.h> #define SHM_SIZE 1024 union semun { int val; struct semid_ds *buf; unsigned short *array; }; //create a semaphore set int createsem(const char *pathname,int proj_id,int num,int init_val) { key_t key; int i,semid; union semun arg; if((key=ftok(pathname,proj_id))==-1) { perror(“ftok error:”); return -1; } if((semid=semget(key,num,IPC_CREAT|IPC_EXCL|0666))==-1) { return -1; } //initialize the value of semaphore arg.val=init_val; for(i=0;i<num;i++) { if(semctl(semid,i,SETVAL,arg)==-1) { perror(“semctl error:”); return -1; } } return (semid); } //open the semaphore set int opensem(const char*pathname,int proj_id) { key_t key; int semid; if((key=ftok(pathname,proj_id))==-1) { perror(“ftok error:”); return -1; } //just get the id of semaphore set if((semid=semget(key,0,IPC_CREAT|0666))==-1) { perror(“semget error:”); return -1; } return (semid); } //P operation int p(int semid,int index) { struct sembuf buf={0,-1,0}; if(index<0) { printf(“error:the index is invalid\n”); return -1; } buf.sem_num=index; if(semop(semid,&buf,1)==-1) { perror(“semop error:”); return -1; } return 1; } //V opeation int v(int semid,int index) { struct sembuf buf={0,+1,0}; if(index<0) { printf(“error:the index is invalid\n”); return -1; } buf.sem_num=index; if(semop(semid,&buf,1)==-1) { perror(“semop error:”); return -1; } return 1; } //delete the semaphore set int deletesem(int semid) { return (semctl(semid,0,IPC_RMID,0)==-1); } //waiting for the semaphore is equal to 1 int waitsem(int semid,int index) { while(semctl(semid,index,GETVAL,0)==0) { sleep(1); printf(“I am waiting for semval equals 1..\n”); } return 1; } //create share memory int createshm(char *pathname,int proj_id,size_t size) { key_t key; int shmid; if((key=ftok(pathname,proj_id))==-1) { perror(“ftok error:”); return -1; } if((shmid=shmget(key,size,IPC_CREAT|IPC_EXCL|0666))==-1) { return -1; } return (shmid); } //open share memory int openshm(char *pathname,int proj_id) { key_t key; int shmid; if((key=ftok(pathname,proj_id))==-1) { perror(“ftok error:”); return -1; } if((shmid=shmget(key,0,IPC_CREAT|0666))==-1) { perror(“shmget error:”); return -1; } return (shmid); }

 

producer.c

  1. #include “shm.h”  
  2.   
  3.   
  4. int main()  
  5. {  
  6.     int num;  
  7.     int shmid_goods,shmid_index,semid;  
  8.     char* shmaddr=NULL;  
  9.     int *indexaddr=NULL;  
  10.     int is_noexist=0;  
  11.   
  12.     num=10;  
  13.     //create a shared memory as goods buffer  
  14.     if((shmid_goods=createshm(“.”,’s’,num))==-1)  
  15.     {  
  16.         if(errno==EEXIST)  
  17.         {  
  18.             if((shmid_goods=openshm(“.”,’s’))==-1)  
  19.             {  
  20.                 exit(1);  
  21.             }  
  22.         }  
  23.         else  
  24.         {  
  25.             perror(”create shared memory failed\n”);  
  26.                 exit(1);  
  27.         }  
  28.     }  
  29.     //attach the shared memory to the current process  
  30.     if((shmaddr=shmat(shmid_goods,(char*)0,0))==(char*)-1)  
  31.     {  
  32.         perror(”attach shared memory error\n”);  
  33.         exit(1);  
  34.     }  
  35.   
  36.     //create a shared memory as index  
  37.     if((shmid_index=createshm(“.”,‘z’,2))==-1)  
  38.     {  
  39.         if(errno==EEXIST)  
  40.         {  
  41.             if((shmid_index=openshm(“.”,‘z’))==-1)  
  42.             {  
  43.                 exit(1);  
  44.             }  
  45.         }  
  46.         else  
  47.         {  
  48.             perror(”create shared memory failed\n”);  
  49.                 exit(1);  
  50.         }  
  51.     }  
  52.     else  
  53.     {  
  54.         is_noexist=1;  
  55.     }  
  56.     //attach the shared memory to the current process  
  57.     if((indexaddr=shmat(shmid_index,(int*)0,0))==(int*)-1)  
  58.     {  
  59.         perror(”attach shared memory error\n”);  
  60.         exit(1);  
  61.     }  
  62.     if(is_noexist)  
  63.     {  
  64.         indexaddr[0]=0;  
  65.         indexaddr[1]=0;  
  66.     }  
  67.   
  68.     //create a semaphore set including 3 semaphores  
  69.     if((semid=createsem(“.”,‘t’,3,0))==-1)  
  70.     {  
  71.         if(errno==EEXIST)  
  72.         {  
  73.             if((semid=opensem(“.”,‘t’))==-1)  
  74.             {  
  75.                 exit(1);  
  76.             }  
  77.         }  
  78.         else  
  79.         {  
  80.             perror(”semget error:”);  
  81.             exit(1);  
  82.         }  
  83.     }  
  84.     else  
  85.     {  
  86.         union semun arg;  
  87.             //seting value for mutex semaphore  
  88.             arg.val=1;  
  89.             if(semctl(semid,0,SETVAL,arg)==-1)  
  90.             {  
  91.             perror(”setting semaphore value failed\n”);  
  92.                 return -1;  
  93.                 }  
  94.             //set value for synchronous semaphore  
  95.             arg.val=num;  
  96.                 //the num means that the producer can continue to produce num products  
  97.             if(semctl(semid,1,SETVAL,arg)==-1)  
  98.                 {  
  99.             perror(”setting semaphore value failed\n”);  
  100.                 return -1;  
  101.             }  
  102.             //the last semaphore’s value is default  
  103.             //the default value ‘0’ means that the consumer is not use any product now  
  104.         }  
  105.   
  106.       
  107.     int goods=0;  
  108.     while(1)  
  109.     {  
  110.         p(semid,1);  
  111.         sleep(3);  
  112.         p(semid,0);  
  113.         //producer is producing a product  
  114.         goods=rand()%10;  
  115.         shmaddr[indexaddr[0]]=goods;  
  116.         printf(”producer:%d produces a product[%d]:%d\n”,getpid(),indexaddr[0],goods);  
  117.         indexaddr[0]=(indexaddr[0]+1)%10;  
  118.         v(semid,0);  
  119.         sleep(3);  
  120.         v(semid,2);  
  121.     }  
  122.   
  123. }  
#include "shm.h"


int main()
{
    int num;
    int shmid_goods,shmid_index,semid;
    char* shmaddr=NULL;
    int *indexaddr=NULL;
    int is_noexist=0;

    num=10;
    //create a shared memory as goods buffer
    if((shmid_goods=createshm(".",'s',num))==-1)
    {
        if(errno==EEXIST)
        {
            if((shmid_goods=openshm(".",'s'))==-1)
            {
                exit(1);
            }
        }
        else
        {
            perror("create shared memory failed\n");
                exit(1);
        }
    }
    //attach the shared memory to the current process
    if((shmaddr=shmat(shmid_goods,(char*)0,0))==(char*)-1)
    {
        perror("attach shared memory error\n");
        exit(1);
    }

    //create a shared memory as index
    if((shmid_index=createshm(".",'z',2))==-1)
    {
        if(errno==EEXIST)
        {
            if((shmid_index=openshm(".",'z'))==-1)
            {
                exit(1);
            }
        }
        else
        {
            perror("create shared memory failed\n");
                exit(1);
        }
    }
    else
    {
        is_noexist=1;
    }
    //attach the shared memory to the current process
    if((indexaddr=shmat(shmid_index,(int*)0,0))==(int*)-1)
    {
        perror("attach shared memory error\n");
        exit(1);
    }
    if(is_noexist)
    {
        indexaddr[0]=0;
        indexaddr[1]=0;
    }

    //create a semaphore set including 3 semaphores
    if((semid=createsem(".",'t',3,0))==-1)
    {
        if(errno==EEXIST)
        {
            if((semid=opensem(".",'t'))==-1)
            {
                exit(1);
            }
        }
        else
        {
            perror("semget error:");
            exit(1);
        }
    }
    else
    {
        union semun arg;
            //seting value for mutex semaphore
            arg.val=1;
            if(semctl(semid,0,SETVAL,arg)==-1)
            {
            perror("setting semaphore value failed\n");
                return -1;
                }
            //set value for synchronous semaphore
            arg.val=num;
                //the num means that the producer can continue to produce num products
            if(semctl(semid,1,SETVAL,arg)==-1)
                {
            perror("setting semaphore value failed\n");
                return -1;
            }
            //the last semaphore's value is default
            //the default value '0' means that the consumer is not use any product now
        }


    int goods=0;
    while(1)
    {
        p(semid,1);
        sleep(3);
        p(semid,0);
        //producer is producing a product
        goods=rand()%10;
        shmaddr[indexaddr[0]]=goods;
        printf("producer:%d produces a product[%d]:%d\n",getpid(),indexaddr[0],goods);
        indexaddr[0]=(indexaddr[0]+1)%10;
        v(semid,0);
        sleep(3);
        v(semid,2);
    }

}

 

consumer.c

  1. #include “shm.h”  
  2.   
  3.   
  4. int main(int argc,char **argv)  
  5. {  
  6.     int num;  
  7.     int shmid_goods,shmid_index,semid;  
  8.     char* shmaddr=NULL;  
  9.     int* indexaddr=NULL;  
  10.     int is_noexist=0;  
  11.   
  12.     num=10;  
  13.     //create a shared memory as goods buffer  
  14.     if((shmid_goods=createshm(“.”,’s’,num))==-1)  
  15.     {  
  16.         if(errno==EEXIST)  
  17.         {  
  18.             if((shmid_goods=openshm(“.”,’s’))==-1)  
  19.             {  
  20.                 exit(1);  
  21.             }  
  22.         }  
  23.         else  
  24.         {  
  25.             perror(”create shared memory failed\n”);  
  26.                 exit(1);  
  27.         }  
  28.     }  
  29.     //attach the shared memory to the current process  
  30.     if((shmaddr=shmat(shmid_goods,(char*)0,0))==(char*)-1)  
  31.     {  
  32.         perror(”attach shared memory error\n”);  
  33.         exit(1);  
  34.     }  
  35.   
  36.     //create a shared memory as index  
  37.     if((shmid_index=createshm(“.”,‘z’,2))==-1)  
  38.     {  
  39.         if(errno==EEXIST)  
  40.         {  
  41.             if((shmid_index=openshm(“.”,‘z’))==-1)  
  42.             {  
  43.                 exit(1);  
  44.             }  
  45.         }  
  46.         else  
  47.         {  
  48.             perror(”create shared memory failed\n”);  
  49.                 exit(1);  
  50.         }  
  51.     }  
  52.     else  
  53.     {  
  54.         is_noexist=1;  
  55.     }  
  56.     //attach the shared memory to the current process  
  57.     if((indexaddr=shmat(shmid_index,(int*)0,0))==(int*)-1)  
  58.     {  
  59.         perror(”attach shared memory error\n”);  
  60.         exit(1);  
  61.     }  
  62.     if(is_noexist)  
  63.     {  
  64.         indexaddr[0]=0;  
  65.         indexaddr[1]=0;  
  66.     }  
  67.   
  68.     //create a semaphore set including 3 semaphores  
  69.     if((semid=createsem(“.”,‘t’,3,0))==-1)  
  70.     {  
  71.         if(errno==EEXIST)  
  72.         {  
  73.             if((semid=opensem(“.”,‘t’))==-1)  
  74.             {  
  75.                 exit(1);  
  76.             }  
  77.         }  
  78.         else  
  79.         {  
  80.             perror(”semget error:”);  
  81.             exit(1);  
  82.         }  
  83.     }  
  84.     else  
  85.     {  
  86.         union semun arg;  
  87.             //seting value for mutex semaphore  
  88.             arg.val=1;  
  89.             if(semctl(semid,0,SETVAL,arg)==-1)  
  90.             {  
  91.             perror(”setting semaphore value failed\n”);  
  92.                 return -1;  
  93.                 }  
  94.             //set value for synchronous semaphore  
  95.             arg.val=num;  
  96.                 //the num means that the producer can continue to produce num products  
  97.             if(semctl(semid,1,SETVAL,arg)==-1)  
  98.                 {  
  99.             perror(”setting semaphore value failed\n”);  
  100.                 return -1;  
  101.             }  
  102.             //the last semaphore’s value is default  
  103.             //the default value ‘0’ means that the consumer is not use any product now  
  104.     }  
  105.   
  106.     int goods=0;  
  107.     while(1)  
  108.     {  
  109.         p(semid,2);  
  110.         sleep(1);  
  111.         p(semid,0);  
  112.         //consumer is consuming a product  
  113.         goods=shmaddr[indexaddr[1]];  
  114.         printf(”consumer:%d consumes a product[%d]:%d\n”,getpid(),indexaddr[1],goods);  
  115.         indexaddr[1]=(indexaddr[1]+1)%num;  
  116.         v(semid,0);  
  117.         sleep(1);  
  118.         v(semid,1);  
  119.     }  
  120.   
  121. }  
#include "shm.h"


int main(int argc,char **argv)
{
    int num;
    int shmid_goods,shmid_index,semid;
    char* shmaddr=NULL;
    int* indexaddr=NULL;
    int is_noexist=0;

    num=10;
    //create a shared memory as goods buffer
    if((shmid_goods=createshm(".",'s',num))==-1)
    {
        if(errno==EEXIST)
        {
            if((shmid_goods=openshm(".",'s'))==-1)
            {
                exit(1);
            }
        }
        else
        {
            perror("create shared memory failed\n");
                exit(1);
        }
    }
    //attach the shared memory to the current process
    if((shmaddr=shmat(shmid_goods,(char*)0,0))==(char*)-1)
    {
        perror("attach shared memory error\n");
        exit(1);
    }

    //create a shared memory as index
    if((shmid_index=createshm(".",'z',2))==-1)
    {
        if(errno==EEXIST)
        {
            if((shmid_index=openshm(".",'z'))==-1)
            {
                exit(1);
            }
        }
        else
        {
            perror("create shared memory failed\n");
                exit(1);
        }
    }
    else
    {
        is_noexist=1;
    }
    //attach the shared memory to the current process
    if((indexaddr=shmat(shmid_index,(int*)0,0))==(int*)-1)
    {
        perror("attach shared memory error\n");
        exit(1);
    }
    if(is_noexist)
    {
        indexaddr[0]=0;
        indexaddr[1]=0;
    }

    //create a semaphore set including 3 semaphores
    if((semid=createsem(".",'t',3,0))==-1)
    {
        if(errno==EEXIST)
        {
            if((semid=opensem(".",'t'))==-1)
            {
                exit(1);
            }
        }
        else
        {
            perror("semget error:");
            exit(1);
        }
    }
    else
    {
        union semun arg;
            //seting value for mutex semaphore
            arg.val=1;
            if(semctl(semid,0,SETVAL,arg)==-1)
            {
            perror("setting semaphore value failed\n");
                return -1;
                }
            //set value for synchronous semaphore
            arg.val=num;
                //the num means that the producer can continue to produce num products
            if(semctl(semid,1,SETVAL,arg)==-1)
                {
            perror("setting semaphore value failed\n");
                return -1;
            }
            //the last semaphore's value is default
            //the default value '0' means that the consumer is not use any product now
    }

    int goods=0;
    while(1)
    {
        p(semid,2);
        sleep(1);
        p(semid,0);
        //consumer is consuming a product
        goods=shmaddr[indexaddr[1]];
        printf("consumer:%d consumes a product[%d]:%d\n",getpid(),indexaddr[1],goods);
        indexaddr[1]=(indexaddr[1]+1)%num;
        v(semid,0);
        sleep(1);
        v(semid,1);
    }

}


 

生产者消费者问题是操作系统中的一个经典的问题。

他描述的是一个,多个生产者与多个消费者共享多个缓冲区的事情,具体的定义百度。

然后看了操作系统的书籍如何解决书上给的伪代码是这样的

item B[k];
semaphore empty;    empty=k;   //可以使用的空缓冲区数
semaphore full; full=0;        //缓冲区内可以使用的产品数
semaphore mutex;    mutex=1;   //互斥信号量
int in=0;                      //放入缓冲区指针
int out=0;                     //取出缓冲区指针 
cobegin
process producer_i ( ) {        process consumer_j( )   {    
       while(true) {                 while(true) {
       produce( );                   P(full);
       P(empty);                     P(mutex);
       P(mutex);                     take( ) from B[out];
       append to B[in];              V(empty);             
       in=(in+1)%k;                  out=(out+1)%k;     
       V(mutex);                     V(mutex);  
       V(full);                      consume( );
                  }                               }
                    }                                }
coend
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

上面的注释,和过程已经比较到位了,只是我习惯用我的方法,即把生产和消费,放入临界区所以下面是我解决生产消费模型所用的伪代码

item B[k];
semaphore empty;    empty=k;   //可以使用的空缓冲区数
semaphore full; full=0;        //缓冲区内可以使用的产品数
semaphore mutex;    mutex=1;   //互斥信号量
int in=0;                      //放入缓冲区指针
int out=0;                     //取出缓冲区指针 
cobegin
process producer_i ( ) {        process consumer_j( )   {    
       while(true) {                  while(true) {
       P(empty);                      P(full);
       P(mutex);                      P(mutex);
       produce( );                    take( ) from B[out];
       append to B[in];               consume( );               
       in=(in+1)%k;                   out=(out+1)%k;     
       V(mutex);                      V(mutex);  
       V(full);                       V(empty);
                  }                               }
                    }                                }
coend
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

好了说了这么多我该帖下我的代码了,此代码在Linux环境下的多线程操作,用到了信号量的。。。

#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <semaphore.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define ERR_EXIT(m) \
        do \
        { \
                perror(m); \
                exit(EXIT_FAILURE); \
        } while(0)

#define CONSUMERS_COUNT 2   //消费者人数
#define PRODUCERS_COUNT 2   //生产者人数 
#define BUFFSIZE 5         

int g_buffer[BUFFSIZE];    //缓冲区数目

unsigned short in = 0;      //放入产品的指针(生产到哪个缓冲区)
unsigned short out = 0;     //取出缓冲区指针 (在哪个缓冲区消费的)
unsigned short produce_id = 0;     
unsigned short consume_id = 0;

sem_t g_sem_full; //可以使用的空缓冲区数(缓冲区中可以生产多少产品)
sem_t g_sem_empty;  //缓冲区内可以使用的产品数(可以消费的产品数)
pthread_mutex_t g_mutex;  //互斥信号量

pthread_t g_thread[CONSUMERS_COUNT + PRODUCERS_COUNT];

void *consume(void *arg)
{
    int i;
    int num = (int)arg;
    while (1)
    {
        printf("%d wait buffer not empty\n", num);
        sem_wait(&g_sem_empty);
        pthread_mutex_lock(&g_mutex);
        //遍历缓冲区,看有哪些缓冲区是可以生产产品的
        for (i = 0; i < BUFFSIZE; i++)
        {
            printf("%02d ", i);
            if (g_buffer[i] == -1)
                printf("%s", "null");
            else
                printf("%d", g_buffer[i]);

            if (i == out)
                printf("\t<--consume");

            printf("\n");
        }
        //produce()操作(生产产品)
        consume_id = g_buffer[out];
        printf("%d begin consume product %d\n", num, consume_id);
        g_buffer[out] = -1;
        //将取出缓冲区的指针偏移1(下个生产的位置)
        out = (out + 1) % BUFFSIZE;
        printf("%d end consume product %d\n", num, consume_id);
        pthread_mutex_unlock(&g_mutex);
        sem_post(&g_sem_full);
        sleep(1);
    }
    return NULL;
}

void *produce(void *arg)
{
    int num = (int)arg;
    int i;
    while (1)
    {
        printf("%d wait buffer not full\n", num);
        sem_wait(&g_sem_full);
        pthread_mutex_lock(&g_mutex);
        for (i = 0; i < BUFFSIZE; i++)
        {
            printf("%02d ", i);
            if (g_buffer[i] == -1)
                printf("%s", "null");
            else
                printf("%d", g_buffer[i]);

            if (i == in)
                printf("\t<--produce");

            printf("\n");
        }

        printf("%d begin produce product %d\n", num, produce_id);
        g_buffer[in] = produce_id;
        in = (in + 1) % BUFFSIZE;
        printf("%d end produce product %d\n", num, produce_id++);
        pthread_mutex_unlock(&g_mutex);
        sem_post(&g_sem_empty);
        sleep(5);
    }
    return NULL;
}

int main(void)
{
    int i;
    for (i = 0; i < BUFFSIZE; i++)
        g_buffer[i] = -1;

    sem_init(&g_sem_full, 0, BUFFSIZE);
    sem_init(&g_sem_empty, 0, 0);

    pthread_mutex_init(&g_mutex, NULL);


    for (i = 0; i < CONSUMERS_COUNT; i++)
        pthread_create(&g_thread[i], NULL, consume, (void *)i);

    for (i = 0; i < PRODUCERS_COUNT; i++)
        pthread_create(&g_thread[CONSUMERS_COUNT + i], NULL, produce, (void *)i);

    for (i = 0; i < CONSUMERS_COUNT + PRODUCERS_COUNT; i++)
        pthread_join(g_thread[i], NULL);

    sem_destroy(&g_sem_full);
    sem_destroy(&g_sem_empty);
    pthread_mutex_destroy(&g_mutex);

    return 0;
}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132

将程序运行,可得到这个结果
这里写图片描述

(function () {('pre.prettyprint code').each(function () { var lines = (this).text().split(\n).length;var numbering = $('
    ').addClass('pre-numbering').hide(); (this).addClass(hasnumbering).parent().append( numbering); for (i = 1; i
    • 0
      点赞
    • 0
      收藏
      觉得还不错? 一键收藏
    • 0
      评论
    #include<windows.h> #include<fstream.h> #include<stdio.h> #include<string> #include<conio.h> //定义一些常量; //本程序允许的最大临界区数; #define MAX_BUFFER_NUM 10 //秒到微秒的乘法因子; #define INTE_PER_SEC 1000 //本程序允许的生产和消费线程的总数; #define MAX_THREAD_NUM 64 //定义一个结构,记录在测试文件中指定的每一个线程的参数 struct ThreadInfo { int serial; //线程序列号 char entity; //是P还是C double delay; //线程延迟 int thread_request[MAX_THREAD_NUM]; //线程请求队列 int n_request; //请求个数 }; //全局变量的定义 //临界区对象的声明,用于管理缓冲区的互斥访问; int Buffer_Critical[MAX_BUFFER_NUM]; //缓冲区声明,用于存放产品; ThreadInfo Thread_Info[MAX_THREAD_NUM]; //线程信息数组; HANDLE h_Thread[MAX_THREAD_NUM]; //用于存储每个线程句柄的数组; HANDLE empty_semaphore; //一个信号量; HANDLE h_mutex; //一个互斥量; HANDLE h_Semaphore[MAX_THREAD_NUM]; //生产者允许消费者开始消费的信号量; CRITICAL_SECTION PC_Critical[MAX_BUFFER_NUM]; DWORD n_Thread = 0; //实际的线程的数目; DWORD n_Buffer_or_Critical; //实际的缓冲区或者临界区的数目; //生产消费及辅助函数的声明 void Produce(void *p); void Consume(void *p); bool IfInOtherRequest(int); int FindProducePositon(); int FindBufferPosition(int); int main(int argc, char **argv) { //声明所需变量; DWORD wait_for_all; ifstream inFile; if (argc!=2) { printf("Usage:%s <File>\n",argv[0]); return 1; } //初始化缓冲区; for(int i=0;i< MAX_BUFFER_NUM;i++) Buffer_Critical[i] = -1; //初始化每个线程的请求队列; for(int j=0;j<MAX_THREAD_NUM;j++) { for(int k=0;k<MAX_THREAD_NUM;k++) Thread_Info[j].thread_request[k] = -1; Thread_Info[j].n_request = 0; } //初始化临界区; for(i =0;i< MAX_BUFFER_NUM;i++) InitializeCriticalSection(&PC_Critical[i]); //打开输入文件,按照规定的格式提取线程等信息; inFile.open(argv[1]); //从文件中获得实际的缓冲区的数目,即测试文件第一行的信息; inFile >> n_Buffer_or_Critical; inFile.get(); // 读取测试文件中的空格,将文件指针指向下一行; printf("输入文件是:\n"); //回显获得的缓冲区的数目信息; printf("%d \n",(int) n_Buffer_or_Critical); //提取每个线程的信息到相应数据结构中; while(inFile){ inFile >> Thread_Info[n_Thread].serial; inFile >> Thread_Info[n_Thread].entity; inFile >> Thread_Info[n_Thread].delay; char c; inFile.get(c); while(c!='\n'&& !inFile.eof()) { inFile>> Thread_Info[n_Thread].thread_request[Thread_Info[n_Thread].n_request++]; inFile.get(c); } n_Thread++; } //回显获得的线程信息,便于确认正确性; for(j=0;j<(int) n_Thread;j++) { int Temp_serial = Thread_Info[j].serial; char Temp_entity = Thread_Info[j].entity; double Temp_delay = Thread_Info[j].delay; printf(" \nthread%2d %c %f ",Temp_serial,Temp_entity,Temp_delay); int Temp_request = Thread_Info[j].n_request; for(int k=0;k<Temp_request;k++) printf(" %d ", Thread_Info[j].thread_request[k]); cout<<endl; } printf("\n\n"); //创建在模拟过程中几个必要的信号量 empty_semaphore = CreateSemaphore(NULL,n_Buffer_or_Critical,n_Buffer_or_Critical, "semaphore_for_empty"); h_mutex = CreateMutex(NULL,FALSE,"mutex_for_update"); //下面这个循环用线程的ID号来为相应生产线程的产品读写时所 //使用的同步信号量命名; for(j=0;j<(int)n_Thread;j++) { char lp[]="semaphore_for_produce_"; int temp =j; while(temp){ char c = (char)(temp%10); strcat(lp,&c); temp/=10; } h_Semaphore[j+1]=CreateSemaphore(NULL,0,n_Thread,lp); } //创建生产者消费者线程; for(i =0;i< (int) n_Thread;i++) { if(Thread_Info[i].entity =='P') h_Thread[i]= CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Produce), &(Thread_Info[i]),0,NULL); else h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Consume), &(Thread_Info[i]),0,NULL); } //主程序等待各个线程的动作结束; wait_for_all = WaitForMultipleObjects(n_Thread,h_Thread,TRUE,-1); printf(" \n \nALL Producer and consumer have finished their work. \n"); printf("Press any key to quit!\n"); _getch(); return 0; } //确认是否还有对同一产品的消费请求未执行; bool IfInOtherRequest(int req) { for(int i=0;i<n_Thread;i++) for(int j=0;j<Thread_Info[i].n_request;j++) if(Thread_Info[i].thread_request[j] == req) return TRUE; return FALSE; } //找出当前可以进行产品生产的空缓冲区位置; int FindProducePosition() { int EmptyPosition; for (int i =0;i<n_Buffer_or_Critical;i++) if(Buffer_Critical[i] == -1) { EmptyPosition = i; //用下面这个特殊值表示本缓冲区正处于被写状态; Buffer_Critical[i] = -2; break; } return EmptyPosition; } //找出当前所需生产者生产的产品的位置; int FindBufferPosition(int ProPos) { int TempPos; for (int i =0 ;i<n_Buffer_or_Critical;i++) if(Buffer_Critical[i]==ProPos){ TempPos = i; break; } return TempPos; } //生产者进程 void Produce(void *p) { //局部变量声明; DWORD wait_for_semaphore,wait_for_mutex,m_delay; int m_serial; //获得本线程的信息; m_serial = ((ThreadInfo*)(p))->serial; m_delay = (DWORD)(((ThreadInfo*)(p))->delay *INTE_PER_SEC); Sleep(m_delay); //开始请求生产 printf("Producer %2d sends the produce require.\n",m_serial); //互斥访问下一个可用于生产的空临界区,实现写写互斥; wait_for_mutex = WaitForSingleObject(h_mutex,-1); //确认有空缓冲区可供生产,同时将空位置数empty减1;用于生产者消费者的同步; //若没有则一直等待,直到消费者进程释放资源为止; wait_for_semaphore = WaitForSingleObject(empty_semaphore,-1); int ProducePos = FindProducePosition(); ReleaseMutex(h_mutex); //生产者在获得自己的空位置并做上标记后,以下的写操作在生产者之间可以并发; //核心生产步骤中,程序将生产者的ID作为产品编号放入,方便消费者识别; printf("Producer %2d begin to produce at position %2d.\n",m_serial,ProducePos); Buffer_Critical[ProducePos] = m_serial; printf("Producer %2d finish producing :\n ",m_serial); printf(" position[ %2d ]:%3d \n\n" ,ProducePos,Buffer_Critical[ProducePos]); //使生产者写的缓冲区可以被多个消费者使用,实现读写同步; ReleaseSemaphore(h_Semaphore[m_serial],n_Thread,NULL); } //消费者进程 void Consume(void * p) { //局部变量声明; DWORD wait_for_semaphore,m_delay; int m_serial,m_requestNum; //消费者的序列号和请求的数目; int m_thread_request[MAX_THREAD_NUM]; //本消费线程的请求队列; //提取本线程的信息到本地; m_serial = ((ThreadInfo*)(p))->serial; m_delay = (DWORD)(((ThreadInfo*)(p))->delay *INTE_PER_SEC); m_requestNum = ((ThreadInfo *)(p))->n_request; for (int i = 0;i<m_requestNum;i++) m_thread_request[i] = ((ThreadInfo*)(p))->thread_request[i]; Sleep(m_delay); //循环进行所需产品的消费 for(i =0;i<m_requestNum;i++){ //请求消费一个产品 printf("Consumer %2d request to consume %2d product\n",m_serial,m_thread_request[i]); //如果对应生产者没有生产,则等待;如果生产了,允许的消费者数目-1;实现了读写同步; wait_for_semaphore=WaitForSingleObject(h_Semaphore[m_thread_request[i]],-1); //查询所需产品放到缓冲区的号 int BufferPos=FindBufferPosition(m_thread_request[i]); //开始进行具体缓冲区的消费处理,读和读在该缓冲区上仍然是互斥的; //进入临界区后执行消费动作;并在完成此次请求后,通知另外的消费者本处请求已 //经满足;同时如果对应的产品使用完毕,就做相应处理;并给出相应动作的界面提 //示;该相应处理指将相应缓冲区清空,并增加代表空缓冲区的信号量; EnterCriticalSection(&PC_Critical[BufferPos]); printf("Consumer %2d begin to consume %2d product \n",m_serial,m_thread_request[i]); ((ThreadInfo*)(p))->thread_request[i] =-1; if(!IfInOtherRequest(m_thread_request[i])) { Buffer_Critical[BufferPos] = -1; //-1标记缓冲区为空; printf("Consumer %2d finish consuming %2d:\n ",m_serial,m_thread_request[i]); printf(" position[ %2d ]:%3d \n\n" ,BufferPos,Buffer_Critical[BufferPos]); ReleaseSemaphore(empty_semaphore,1,NULL); } else { printf("Consumer %2d finish consuming product %2d\n\n ",m_serial,m_thread_request[i]); } //离开临界区 LeaveCriticalSection(&PC_Critical[BufferPos]); } }
    1、实验目的 (1)掌握基本的同步互斥算法,理解生产者消费者同步的问题模型。 (2)了解Windows 2000/XP中多线程的并发执行机制,线程间的同步和互斥。 (3)学习使用Windows2000/XP中基本的同步对象,掌握相应的API。 2、实验要求 (1)创建生产者消费者线程 在Windows2000环境下,创建一个控制台进程,在此进程中创建n个线程来模拟生产者或者消费者。这些线程的信息由本程序定义的“测试用例文件”中予以指定。 该文件的格式和含义如下: 3 1 P 3 2 P 4 3 C 4 1 4 P 2 5 C 3 1 2 4 第一行说明程序中设置几个临界区,其余每行分别描述了一个生产者或者消费者线程的信息。每一行的各字段间用Tab键隔开。不管是消费者还是生产者,都有一个对应的线程号,即每一行开始字段那个整数。第二个字段用字母P或者C区分是生产者还是消费者。第三个字段表示在进入相应线程后,在进行生产和消费动作前的休眠时间,以秒计时;这样做的目的是可以通过调整这一列参数,控制开始进行生产和消费动作的时间。如果是代表生产者,则该行只有三个字段。如果代表消费者,则该行后边还有若干字段,代表要求消费的产品所对应的生产者的线程号。所以务必确认这些对应的线程号存在并且该线程代表一个生产者。 (2)生产和消费的规则 在按照上述要求创建线程进行相应的读写操作时,还需要符合以下要求: ①共享缓冲区存在空闲空间时,生产者即可使用共享缓冲区。 ②从上边的测试数据文件例子可以看出,某一生产者生产一个产品后,可能不止一个消费者,或者一个消费者多次地请求消费该产品。此时,只有当所有的消费需求都被满足以后,该产品所在的共享缓冲区才可以被释放,并作为空闲空间允许新的生产者使用。 ③每个消费者线程的各个消费需求之间存在先后顺序。例如上述测试用例文件包含一行信息“5 C 3 l 2 4”,可知这代表一个消费者线程,该线程请求消费1,2,4号生产者线程生产的产品。而这种消费是有严格顺序的,消费1号线程产品的请求得到满足后才能继续往下请求2号生产者线程的产品。 ④要求在每个线程发出读写操作申请、开始读写操作和结束读写操作时分别显示提示信息。 (3)相关基础知识 本实验所使用的生产者消费者模型具有如下特点: 本实验的多个缓冲区不是环形循环的,也不要求按顺序访问。生产者可以把产品放到目前某一个空缓冲区中。 消费者消费指定生产者的产品。 在测试用例文件中指定了所有的生产和消费的需求,只有当共享缓冲区的数据满足了所有关于它的消费需求后,此共享缓冲区才可以作为空闲空间允许新的生产者使用。 本实验在为生产者分配缓冲区时各生产者间必须互斥,此后各个生产者的具体生产活动可以并发。而消费者之间只有在对同一产品进行消费时才需要互斥,同时它们在消费过程结束时需要判断该消费对象是否已经消费完毕并清除该产品。 Windows用来实现同步和互斥的实体。在Windows中,常见的同步对象有:信号量(Semaphore)、互斥量(Mutex)、临界段(CriticalSection)等。使用这些对象都分为三个步骤,一是创建或者初始化:接着请求该同步对象,随即进入临界区,这一步对应于互斥量的上锁;最后释放该同步对象,这对应于互斥量的解锁。这些同步对象在一个线程中创建,在其他线程中都可以使用,从而实现同步互斥。

    “相关推荐”对你有帮助么?

    • 非常没帮助
    • 没帮助
    • 一般
    • 有帮助
    • 非常有帮助
    提交
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值