一生有你llx 阅读(91) 评论(0)
一、为什么要使用条件变量
    一个典型的实例:
    在一条生产先线上有一个仓库,当生产者生产的时候需要锁住仓库独占,而消费者取产品的时候也要锁住仓库独占。如果生产者发现仓库满了,那么他就不能生产了,变成了阻塞状态。但是此时由于生产者独占仓库,消费者又无法进入仓库去消耗产品,这样就造成了一个僵死状态。

    我们需要一种机制,当互斥量被锁住以后发现当前线程还是无法完成自己的操作,那么它应该释放互斥量,让其他线程工作。
    1、可以采用轮询的方式,不停的查询你需要的条件
    2、让系统来帮你查询条件,使用条件变量pthread_cond_t cond

二、条件变量初始化与销毁
    条件变量使用之前需要初始化:
     1、pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
    2、int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
         默认属性为空NULL

    条件变量使用完成之后需要销毁
    int pthread_cond_destroy(pthread_cond_t *cond);

三、如何使用条件变量
    条件变量使用需要配合互斥量
    int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
    1、使用pthread_cond_wait等待条件变为真。传递给pthread_cond_wait的互斥量对条件进行保护,调用者把锁住的互斥量传递给函数。
    2、这个函数将线程放到等待条件的线程列表上,然后对互斥量进行解锁,这是个原子操作。当条件满足时这个函数返回,返回以后继续对互斥量加锁。

    int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
    3、这个函数与pthread_cond_wait类似,只是多一个timeout,如果到了指定的时间条件还不满足,那么就返回。时间用下面的结构体表示
     struct timespec{
         time_t tv_sec;
         long tv_nsec;
     };
    注意,这个时间是绝对时间。例如你要等待3分钟,就要把当前时间加上3分钟然后转换到 timespec,而不是直接将3分钟转换到 timespec

    当条件满足的时候,需要唤醒等待条件的线程
    int pthread_cond_broadcast(pthread_cond_t *cond);
    int pthread_cond_signal(pthread_cond_t *cond);
    1、pthread_cond_broadcast唤醒等待条件的所有线程
    2、pthread_cond_signal至少唤醒等待条件的某一个线程
     注意,一定要在条件改变以后在唤醒线程

四、手册
PTHREAD_COND_DESTROY(3P)   POSIX Programmer’s Manual  PTHREAD_COND_DESTROY(3P)

PROLOG
       This  manual page is part of the POSIX Programmer’s Manual.  The Linux implementation of this interface may differ (con-
       sult the corresponding Linux manual page for details of Linux behavior), or the interface  may  not  be  implemented  on
       Linux.
     //这只是POSIX的手册,Linux对这个接口的实现可能不一样,或者有的根本没有实现这个接口

NAME
       pthread_cond_destroy, pthread_cond_init - destroy and initialize condition variables
        //销毁或者初始化一个条件变量

SYNOPSIS
       #include <pthread.h>
        //包含头文件

       int pthread_cond_destroy(pthread_cond_t *cond);
       int pthread_cond_init(pthread_cond_t *restrict cond,
              const pthread_condattr_t *restrict attr);
       pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

DESCRIPTION
       The pthread_cond_destroy() function shall destroy the given condition variable specified by cond; the object becomes, in
       effect, uninitialized. An implementation may cause pthread_cond_destroy() to set the object referenced  by  cond  to  an
       invalid value. A destroyed condition variable object can be reinitialized using pthread_cond_init(); the results of oth-
       erwise referencing the object after it has been destroyed are undefined.
        //pthread_cond_destroy()会销毁一个条件变量,让它变的无效。一个被销毁的条件变量可以被重新初始化,多次销毁的结果
        //是未知的


       It shall be safe to destroy an initialized condition variable upon which no threads are currently blocked. Attempting to
       destroy a condition variable upon which other threads are currently blocked results in undefined behavior.
        //当没有现成因为条件变量阻塞的时候,销毁条件变量是安全的,否则就会导致未知的结果

       The  pthread_cond_init()  function shall initialize the condition variable referenced by cond with attributes referenced
       by attr. If attr is NULL, the default condition variable attributes shall be used; the effect is the same as passing the
       address  of  a  default condition variable attributes object. Upon successful initialization, the state of the condition
       variable shall become initialized.
        //pthread_cond_init() 会用给定的属性去初始化一个条件变量,如果属性为NULL那么就是默认的属性。

       Only cond itself may be used for performing synchronization.  The result of referring to copies  of  cond  in  calls  to
       pthread_cond_wait(),       pthread_cond_timedwait(),      pthread_cond_signal(),      pthread_cond_broadcast(),      and
       pthread_cond_destroy() is undefined.
        //只有条件变量自身才可以同步,重复的在 pthread_cond_wait(),       pthread_cond_timedwait(),      pthread_cond_signal(),                      //pthread_cond_broadcast(),   pthread_cond_destroy() 等这些函数中调用cond会导致未知的结果

       Attempting to initialize an already initialized condition variable results in undefined behavior.
        //试图去初始化一个已经被初始化的条件变量会导致未知的结果

       In cases where default condition variable attributes are appropriate, the macro PTHREAD_COND_INITIALIZER can be used  to
       initialize  condition  variables that are statically allocated. The effect shall be equivalent to dynamic initialization
       by a call to pthread_cond_init() with parameter attr specified as NULL, except that no error checks are performed.
        //可以使用PTHREAD_COND_INITIALIZER 去初始化一个静态的条件变量(默认属性),或者使用pthread_cond_init() 去动态
        //的初始化条件变量


RETURN VALUE
       If successful, the pthread_cond_destroy() and pthread_cond_init() functions shall return zero; otherwise, an error  num-
       ber shall be returned to indicate the error.
        //成功返回0,失败返回错误码

       The  [EBUSY] and [EINVAL] error checks, if implemented, shall act as if they were performed immediately at the beginning
       of processing for the function and caused an error return prior to modifying the state of the condition variable  speci-
       fied by cond.
        //如果 [EBUSY] and [EINVAL]的错误检查功能被实现了,那么他们看起来好像在进程的一开始就已经工作了,当你去修改条件
        //变量是属性的时候,错误码会立刻被返回


ERRORS
       The pthread_cond_destroy() function may fail if:
        // pthread_cond_destroy() 会在以下情况失败

       EBUSY  The  implementation  has detected an attempt to destroy the object referenced by cond while it is referenced (for
              example, while being used in a pthread_cond_wait() or pthread_cond_timedwait()) by another thread.
                //当有线程正在使用条件变量的时候,那么销毁救护失败

       EINVAL The value specified by cond is invalid.
                //是一个无效的条件变量

       The pthread_cond_init() function shall fail if:
        //pthread_cond_init()会在以下情况失败

       EAGAIN The system lacked the necessary resources (other than memory) to initialize another condition variable.
                    //系统缺少必要的资源去初始化(不是内存)

       ENOMEM Insufficient memory exists to initialize the condition variable.
                //系统缺内存去初始化条件变量

       The pthread_cond_init() function may fail if:
        //pthread_cond_init()还有可能因为以下情况失败

       EBUSY  The implementation has detected an attempt to reinitialize the object referenced by cond, a  previously  initial-
              ized, but not yet destroyed, condition variable.
                //试图去重新初始化一个已经被初始化但是没有销毁的互斥量

       EINVAL The value specified by attr is invalid.
                //给定的属性是无效的

       These functions shall not return an error code of [EINTR].
        //不会返回EINTR



PTHREAD_COND_TIMEDWAIT(3P) POSIX Programmer’s ManualPTHREAD_COND_TIMEDWAIT(3P)
PROLOG
       This  manual page is part of the POSIX Programmer’s Manual.  The Linux implementation of this interface may differ (con-
       sult the corresponding Linux manual page for details of Linux behavior), or the interface  may  not  be  implemented  on
       Linux.
    //这只是POSIX的手册,Linux对这个接口的实现可能不一样,或者有的根本没有实现这个接口

NAME
       pthread_cond_timedwait, pthread_cond_wait - wait on a condition


SYNOPSIS
       #include <pthread.h>
        //包含头文件

       int pthread_cond_timedwait(pthread_cond_t *restrict cond,  pthread_mutex_t *restrict mutex,  const struct timespec *restrict abstime);
       int pthread_cond_wait(pthread_cond_t *restrict cond,  pthread_mutex_t *restrict mutex);

DESCRIPTION
       The pthread_cond_timedwait() and pthread_cond_wait() functions shall block on a condition variable. They shall be called
       with mutex locked by the calling thread or undefined behavior results.
        //pthread_cond_timedwait() and pthread_cond_wait()会阻塞一个条件变量,他们应该配合互斥量使用,否则结果是未知的

       These functions atomically release mutex and cause the calling thread to block on the condition  variable  cond;  atomi-
       cally  here  means  "atomically  with respect to access by another thread to the mutex and then the condition variable".
       That is, if another thread is able to acquire the mutex after the about-to-block thread has released it, then  a  subse-
       quent  call  to pthread_cond_broadcast() or pthread_cond_signal() in that thread shall behave as if it were issued after
       the about-to-block thread has blocked.
        //这个函数会将mutex释放,同时将线程阻塞,这是一个原子操作。其他的线程就可以去拥有互斥量了,然后释放一个信号
        //通知其他阻塞的线程,条件已经被满足了

       Upon successful return, the mutex shall have been locked and shall be owned by the calling thread.
        //成功的返回之后,互斥量被加锁,被当前线程拥有

       When using condition variables there is always a Boolean predicate involving shared variables associated with each  con-
       dition  wait  that  is  true  if  the  thread  should  proceed.  Spurious  wakeups  from the pthread_cond_timedwait() or
       pthread_cond_wait() functions may occur. Since the return from pthread_cond_timedwait() or pthread_cond_wait() does  not
       imply anything about the value of this predicate, the predicate should be re-evaluated upon such return.
        //使用条件变量的时候通常配有一个布尔类型的变量,如果这个变量是真,那么线程就应该向前执行。pthread_cond_timedwait()
        //or pthread_cond_wait()并不知道这个变量的值,因此当他们返回之后,这个变量要重新被赋值 

       The effect of using more than one mutex for concurrent pthread_cond_timedwait() or pthread_cond_wait() operations on the
       same condition variable is undefined; that is, a condition variable becomes bound to a unique mutex when a thread  waits
       on the condition variable, and this (dynamic) binding shall end when the wait returns.
        //一个条件变量只绑定一个互斥量使用,如果有多个互斥量绑定了同一个条件变量,那么结果是未知的

       A  condition wait (whether timed or not) is a cancellation point. When the cancelability enable state of a thread is set
       to PTHREAD_CANCEL_DEFERRED, a side effect of acting upon a cancellation request while in a condition wait  is  that  the
       mutex  is  (in effect) re-acquired before calling the first cancellation cleanup handler. The effect is as if the thread
       were unblocked, allowed to execute  up  to  the  point  of  returning  from  the  call  to  pthread_cond_timedwait()  or
       pthread_cond_wait(),  but  at  that  point  notices  the  cancellation request and instead of returning to the caller of
       pthread_cond_timedwait() or pthread_cond_wait(), starts the thread cancellation activities, which includes calling  can-
       cellation cleanup handlers.
        //条件等待是一个取消点。当线程的取消状态是延迟的,那么在条件等待的时候取消一个线程会导致互斥量被重新获取。

       A  thread  that  has  been unblocked because it has been canceled while blocked in a call to pthread_cond_timedwait() or
       pthread_cond_wait() shall not consume any condition signal that may be directed concurrently at the  condition  variable
       if there are other threads blocked on the condition variable.
        //如果一个线程阻塞在pthread_cond_timedwait() 或pthread_cond_wait(),取消它将导致它变的不阻塞,也不回发生任何信号

       The  pthread_cond_timedwait()  function  shall be equivalent to pthread_cond_wait(), except that an error is returned if
       the absolute time specified by abstime passes (that is, system time equals or exceeds abstime) before the condition cond
       is  signaled  or  broadcasted,  or  if the absolute time specified by abstime has already been passed at the time of the
       call.
        //pthread_cond_timedwait() 和 pthread_cond_wait()几乎是等价的,除了pthread_cond_timedwait() 会产生一个超时信号

       If the Clock Selection option is supported, the condition variable shall have a  clock  attribute  which  specifies  the
       clock  that  shall  be  used  to  measure  the  time  specified  by  the  abstime  argument.   When such timeouts occur,
       pthread_cond_timedwait() shall nonetheless release and re-acquire the mutex referenced by mutex. The pthread_cond_timed-
       wait() function is also a cancellation point.
       //如果时钟选项被支持,那么条件变量会有一个时钟的属性去测量时间。如果时间到了,那么 pthread_cond_timedwait()会返回
        //而且重新去获取互斥量。pthread_cond_timedwait()也是一个取消点

       If  a  signal  is delivered to a thread waiting for a condition variable, upon return from the signal handler the thread
       resumes waiting for the condition variable as if it was not interrupted, or it shall return zero due to spurious wakeup.
        //如果有信号发送给等待条件的线程,那么当信号处理函数返回之后,线程继续等待条件变量,好像它从未被打断

RETURN VALUE
       Except  in the case of [ETIMEDOUT], all these error checks shall act as if they were performed immediately at the begin-
       ning of processing for the function and shall cause an error return, in effect, prior to  modifying  the  state  of  the
       mutex specified by mutex or the condition variable specified by cond.
        //除了ETIMEDOUT,其他所有的错误检测就好像在线程的一开始就已经工作了

       Upon  successful completion, a value of zero shall be returned; otherwise, an error number shall be returned to indicate
       the error.
        //成功的返回0,失败返回错误码

ERRORS
       The pthread_cond_timedwait() function shall fail if:
        //pthread_cond_timedwait() 会在一下情况失败

       ETIMEDOUT
              The time specified by abstime to pthread_cond_timedwait() has passed.
                //设定的超时时间已经过了

       The pthread_cond_timedwait() and pthread_cond_wait() functions may fail if:
        //pthread_cond_timedwait() 和pthread_cond_wait()会在以下情况失败

       EINVAL The value specified by cond, mutex, or abstime is invalid.
                    //指定的条件变量、互斥量、时间无效

       EINVAL Different mutexes were supplied for concurrent pthread_cond_timedwait() or pthread_cond_wait() operations on  the
              same condition variable.
                    //对一个条件变量绑定了不同的互斥量

       EPERM  The mutex was not owned by the current thread at the time of the call.
                    //互斥量不被当前线程拥有

       These functions shall not return an error code of [EINTR].
        //不会返回EINTR    


PTHREAD_COND_BROADCAST(3P) POSIX Programmer’s ManualPTHREAD_COND_BROADCAST(3P)
PROLOG
       This  manual page is part of the POSIX Programmer’s Manual.  The Linux implementation of this interface may differ (con-
       sult the corresponding Linux manual page for details of Linux behavior), or the interface  may  not  be  implemented  on
       Linux.
        //这只是POSIX的手册,Linux对这个接口的实现可能不一样,或者有的根本没有实现这个接口

NAME
       pthread_cond_broadcast, pthread_cond_signal - broadcast or signal a condition
        //广播或者发送一个条件

SYNOPSIS
       #include <pthread.h>
        //包含头文件

       int pthread_cond_broadcast(pthread_cond_t *cond);
       int pthread_cond_signal(pthread_cond_t *cond);


DESCRIPTION
       These functions shall unblock threads blocked on a condition variable.
        //在条件满足的情况下解锁一个阻塞的线程

       The  pthread_cond_broadcast()  function  shall unblock all threads currently blocked on the specified condition variable
       cond.
        //pthread_cond_broadcast()将当前所有因为这个条件阻塞的线程解锁

       The pthread_cond_signal() function shall unblock at least one of the threads that are blocked on the specified condition
       variable cond (if any threads are blocked on cond).
        //解锁至少一个因为这个条件阻塞的线程

       If  more  than  one  thread is blocked on a condition variable, the scheduling policy shall determine the order in which
       threads are unblocked. When each thread unblocked as a result of  a  pthread_cond_broadcast()  or  pthread_cond_signal()
       returns  from  its call to pthread_cond_wait() or pthread_cond_timedwait(), the thread shall own the mutex with which it
       called pthread_cond_wait() or pthread_cond_timedwait(). The thread(s) that are unblocked shall  contend  for  the  mutex
       according to the scheduling policy (if applicable), and as if each had called pthread_mutex_lock().
        //如果有多个线程因为条件阻塞,那么系统调度会决定让哪一个线程解锁。解锁的那个线程会拥有互斥量

       The  pthread_cond_broadcast()  or  pthread_cond_signal() functions may be called by a thread whether or not it currently
       owns the mutex that threads calling pthread_cond_wait() or pthread_cond_timedwait() have associated with  the  condition
       variable during their waits; however, if predictable scheduling behavior is required, then that mutex shall be locked by
       the thread calling pthread_cond_broadcast() or pthread_cond_signal().


       The pthread_cond_broadcast() and pthread_cond_signal() functions shall have no effect if there are no threads  currently
       blocked on cond.
        //如果当前没有线程阻塞,那么这两个函数就没有任何效果

RETURN VALUE
       If  successful,  the pthread_cond_broadcast() and pthread_cond_signal() functions shall return zero; otherwise, an error
       number shall be returned to indicate the error.
        //成功返回0,失败返回错误码

ERRORS
       The pthread_cond_broadcast() and pthread_cond_signal() function may fail if:
        //以下情况会导致失败

       EINVAL The value cond does not refer to an initialized condition variable.
                    //条件变量没有初始化

       These functions shall not return an error code of [EINTR].
        //不会返回EINTR

EXAMPLES
       None.

五、实例,生产者与消费者问题
    1、程序框架

    2、源代码

点击(此处)折叠或打开

  1. /*DATE:    2015-4-6
  2.  *AUTHOR:DDDDD
  3.  *DESCRIPTION: 生产者与消费者问题
  4.  */

  5. #include "apue.h"
  6.   
  7. #define BUFFER_SIZE 5 //产品库存大小
  8. #define PRODUCT_CNT 30 //产品生产总数
  9.   
  10. struct product_cons
  11. {
  12.     int buffer[BUFFER_SIZE]; //生产产品值
  13.     pthread_mutex_t lock; //互斥锁 volatile int
  14.     int readpos, writepos; //读写位置
  15.     pthread_cond_t notempty; //条件变量,非空
  16.     pthread_cond_t notfull; //非满
  17. }buffer;
  18.   
  19. void init(struct product_cons *p)
  20. {
  21.     pthread_mutex_init(&p->lock, NULL); //互斥锁
  22.     pthread_cond_init(&p->notempty, NULL); //条件变量
  23.     pthread_cond_init(&p->notfull, NULL); //条件变量
  24.     p->readpos = 0; //读写位置
  25.     p->writepos = 0;
  26. }
  27.   
  28. void finish(struct product_cons *p)
  29. {
  30.     pthread_mutex_destroy(&p->lock); //互斥锁
  31.     pthread_cond_destroy(&p->notempty); //条件变量
  32.     pthread_cond_destroy(&p->notfull); //条件变量
  33.     p->readpos = 0; //读写位置
  34.     p->writepos = 0;
  35. }
  36.   
  37.   
  38. //存储 一个数据 到 bufferr
  39. void put(struct product_cons *p, int data) //输入产品子函数
  40. {
  41.     pthread_mutex_lock(&p->lock);
  42.     if((p->writepos+1)%BUFFER_SIZE == p->readpos)
  43.     {
  44.         printf("producer wait for not full\n");
  45.         pthread_cond_wait(&p->notfull, &p->lock);
  46.     }

  47.     p->buffer[p->writepos] = data;
  48.     p->writepos ++;

  49.     if(p->writepos >= BUFFER_SIZE)
  50.         p->writepos = 0;

  51.     pthread_cond_signal(&p->notempty);
  52.     pthread_mutex_unlock(&p->lock);
  53. }

  54. //读,移除 一个数据 从 buffer
  55. int get(struct product_cons *p)
  56. {
  57.     int data;

  58.     pthread_mutex_lock(&p->lock);

  59.     if(p->readpos == p->writepos)
  60.     {
  61.         printf("consumer wait for not empty\n");
  62.         pthread_cond_wait(&p->notempty, &p->lock);
  63.     }

  64.     data = p->buffer[p->readpos];
  65.     p->readpos++;

  66.     if(p->readpos >= BUFFER_SIZE)
  67.         p->readpos = 0;

  68.     pthread_cond_signal(&p->notfull);

  69.     pthread_mutex_unlock(&p->lock);

  70.     return data;
  71. }

  72. void *producer(void *data) //子线程 ,生产
  73. {
  74.     int n;
  75.     for(n = 1; n <= 50; ++n) //生产 50 个产品
  76.     {
  77.         sleep(1);
  78.         printf("put the %d product ...\n", n);
  79.         put(&buffer,n);
  80.         printf("put the %d product success\n", n);
  81.     }

  82.     printf("producer stopped\n");

  83.     return NULL;
  84. }

  85. void *consumer(void *data)
  86. {
  87.     static int cnt = 0;
  88.     int num;
  89.     while(1)
  90.     {
  91.         sleep(2);
  92.         printf("get product ...\n");
  93.         num = get(&buffer);
  94.         printf("get the %d product success\n", num);
  95.         if(++cnt == PRODUCT_CNT)
  96.             break;
  97.     }

  98.     printf("consumer stopped\n");
  99.     return NULL;
  100. }

  101. int main(int argc, char *argv[])
  102. {
  103.     pthread_t th_a,th_b;
  104.     void *retval;

  105.     init(&buffer);

  106.     pthread_create(&th_a, NULL, producer, 0);
  107.     pthread_create(&th_b, NULL, consumer, 0);

  108.     pthread_join(th_a, &retval);
  109.     pthread_join(th_b, &retval);

  110.     finish(&buffer);

  111.     return 0;
  112. }
    3、作业:多个生产者与多个消费者

点击(此处)折叠或打开

  1. /*多个生产者和多个消费者*/

  2. #include "apue.h"


  3. #define BUFFER_SIZE 5 //产品库存大小
  4. #define PRODUCT_CNT 50 //产品生产总数

  5. struct product_cons
  6. {
  7.     int buffer[BUFFER_SIZE]; //生产产品值
  8.     pthread_mutex_t lock; //互斥锁 volatile int
  9.     int readpos, writepos; //读写位置
  10.     pthread_cond_t notempty; //条件变量,非空
  11.     pthread_cond_t notfull; //非满

  12.     pthread_mutex_t lock2; //互斥锁,控制cnt_p
  13.     int cnt_p; //完成生产产品数量

  14.     pthread_mutex_t lock3; //互斥锁,控制cnt_c
  15.     int cnt_c; //获得生产产品数量
  16. }buffer;

  17. void init(struct product_cons *p)
  18. {
  19.     pthread_mutex_init(&p->lock, NULL); //互斥锁
  20.     pthread_cond_init(&p->notempty, NULL); //条件变量
  21.     pthread_cond_init(&p->notfull, NULL); //条件变量
  22.     p->readpos = 0; //读写位置
  23.     p->writepos = 0;

  24.     pthread_mutex_init(&p->lock2, NULL);
  25.     p->cnt_p = 0;

  26.     pthread_mutex_init(&p->lock3, NULL);
  27.     p->cnt_c = 0;
  28. }

  29. void fini(struct product_cons *p)
  30. {
  31.     pthread_mutex_destroy(&p->lock); //互斥锁
  32.     pthread_cond_destroy(&p->notempty); //条件变量
  33.     pthread_cond_destroy(&p->notfull); //条件变量
  34.     p->readpos = 0; //读写位置
  35.     p->writepos = 0;

  36.     pthread_mutex_destroy(&p->lock2);
  37.     p->cnt_p = 0;

  38.     pthread_mutex_destroy(&p->lock3);
  39.     p->cnt_c = 0;
  40. }

  41. //存储 一个数据 到 bufferr
  42. void put(struct product_cons *p, int data) //输入产品子函数
  43. {
  44.     pthread_mutex_lock(&p->lock); //上锁
  45.         
  46.     /*等待,直到 buffer 不为 满*/
  47.     while((p->writepos + 1) % BUFFER_SIZE == p->readpos) //测试空间是否已满
  48.     {
  49.         printf("producer wait for not full\n");
  50.         pthread_cond_wait(&p->notfull, &p->lock); //阻塞等待
  51.         //这里,生产者 notfull 等待消费者 pthread_cond_signal(&p->notfull);信号
  52.         //如果,消费者发送了 signal 信号,表示有了 空闲
  53.     }

  54.     p->buffer[p->writepos] = data; //写数据
  55.     p->writepos++;

  56.     if(p->writepos >= BUFFER_SIZE) //如果写到 尾部,返回
  57.         p->writepos = 0;
  58.         
  59.     pthread_cond_signal(&p->notempty); //发送有数据信号
  60.     pthread_mutex_unlock(&p->lock); //解锁
  61. }

  62. //读,移除 一个数据 从 buffer
  63. int get(struct product_cons *p)
  64. {
  65.     int data = 0;
  66.     pthread_mutex_lock(&p->lock);

  67.     /*等待,直到不为空*/
  68.     while(p->writepos == p->readpos)
  69.     {
  70.         printf("consumer wait for not empty\n");
  71.         pthread_cond_wait(&p->notempty,&p->lock);
  72.     }

  73.     /*读 一个 数据*/
  74.     data = p->buffer[p->readpos];
  75.     p->readpos++;

  76.     if(p->readpos >= BUFFER_SIZE) //如果读到 尾
  77.         p->readpos = 0;

  78.     pthread_cond_signal(&p->notfull);
  79.     pthread_mutex_unlock(&p->lock);

  80.     return data;
  81. }

  82. void *producer(void *data) //子线程 ,生产
  83. {
  84.     int flag = -1;
  85.     while(1)
  86.     {
  87.         pthread_mutex_lock(&buffer.lock2);
  88.         if(buffer.cnt_p < PRODUCT_CNT)
  89.         {
  90.             ++buffer.cnt_p;
  91.             printf("%s put the %d product\n", (char*)data, buffer.cnt_p);
  92.             put(&buffer, buffer.cnt_p);
  93.         }
  94.         else
  95.             flag = 0;
  96.         pthread_mutex_unlock(&buffer.lock2);

  97.         if(!flag)
  98.             break;

  99.         sleep(2);
  100.     }

  101.     printf("%s producer stopped\n", (char*)data);
  102.     return NULL;
  103. }

  104. void *consumer(void *data)
  105. {
  106.     int flag = -1;
  107.     while(1)
  108.     {
  109.         pthread_mutex_lock(&buffer.lock3);
  110.         if(buffer.cnt_c < PRODUCT_CNT)
  111.         {
  112.             printf("%s get the %d product\n", (char*)data, get(&buffer));
  113.             ++buffer.cnt_c;
  114.         }
  115.         else
  116.             flag = 0;
  117.         pthread_mutex_unlock(&buffer.lock3);
  118.         if(!flag)
  119.             break;

  120.         sleep(2);
  121.     }
  122.         
  123.     printf("%s consumer stopped\n", (char*)data);
  124.     return NULL;
  125. }

  126. int main(int argc, char *argv[])
  127. {
  128.     pthread_t th_a[3],th_b[3];
  129.     void *retval;
  130.         
  131.     init(&buffer);
  132.         
  133.     pthread_create(&th_a[0], NULL, producer, (void*)"th_a[0]");
  134.     pthread_create(&th_a[1], NULL, producer, (void*)"th_a[1]");
  135.     pthread_create(&th_a[2], NULL, producer, (void*)"th_a[2]");
  136.     pthread_create(&th_b[0], NULL, consumer, (void*)"th_b[0]");
  137.     pthread_create(&th_b[1], NULL, consumer, (void*)"th_b[1]");
  138.     pthread_create(&th_b[2], NULL, consumer, (void*)"th_b[2]");

  139.     pthread_join(th_a[0], &retval);
  140.     pthread_join(th_a[1], &retval);
  141.     pthread_join(th_a[2], &retval);
  142.     pthread_join(th_b[0], &retval);
  143.     pthread_join(th_b[1], &retval);
  144.     pthread_join(th_b[2], &retval);

  145.     fini(&buffer);

  146.     return 0;
  147. }