代码中用到了互斥锁和条件变量。简单的介绍一下:
  互斥锁
  为了实现生产者与消费者之间的互斥关系,我们用到了互斥锁。你可以把他想象成一把锁,只有拿到这把锁的人才能访问资源,而拿不到锁只能等待,直到锁资源被释放。
  pthread_mutex_t
  用它可以声明一个锁,再初始化它,如果像我们上面的代码一样,mutex变量时全局的,或者静态的,可以?宏定义PTHREAD_MUTEX_INITIALIZER来初始化。否则使用函数初始化,初始化函数:
  int pthread_mutex_init(pthread_mutex_t *restrict mutex,
  const pthread_mutexattr_t *restrict attr);
  函数具体怎么用可以在Linux下使用:man 函数名。查看函数用法和详细信息。
  加锁函数:
  int pthread_mutex_lock(pthread_mutex_t *mutex);
  线程可以使用它获得mutex,如果当前mutex已经被其他线程申请到了,那么当前线程只能挂起等待,知道其他线程释放mutex。释放mutex的函数:
  int pthread_mutex_unlock(pthread_mutex_t *mutex);
  如果?个线程既想获得锁,又不想挂起等待,可以调?:
  int pthread_mutex_trylock(pthread_mutex_t *mutex);
  如果Mutex已经被另一个线程获得,这个函数会失败返回EBUSY,?不会使线程挂起等待。
  条件变量
  在上面的代码中,我们使用条件变量保证了生产者和消费者之间的同步。怎么做到的呢?
  pthread_cond_t    //声明条件变量
  初始化和mutex一样,可分别用宏或者函数。
  int pthread_cond_init(pthread_cond_t *restrict cond,
  const pthread_condattr_t *restrict attr);
  //初始化
  int pthread_cond_wait(pthread_cond_t *restrict cond,
  pthread_mutex_t *restrict mutex);
  一个线程可以调用
  pthread_cond_wait在一个Condition Variable上阻塞等待,这个函数做以下三步操作:
  1>释放Mutex
  2> 阻塞等待
  3>当被唤醒时,重新获得Mutex并返回。
  上面的代码我们在链表中无数据时wait。在生产者生产完数据时,使用
  pthread_cond_signal唤醒在Condition Variable上等待的消费者线程。
  int pthread_cond_signal(pthread_cond_t *cond);
  2.多生产者多消费者。
  要模拟此模型,我们要多考虑两种关系,即前面提到的,保证生产者与生产者,消费者与消费者之间的互斥关系。除此之外,使用一个环形Buffer作为缓冲区。

  生产者关心的是有无空的格子,消费者关心有无数据。所以,这个模型里面我们用到了信号量,用它来表示格子和数据的数量。
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>
#include<stdlib.h>
#define _SIZE_ 64     //环形队列大小64
sem_t blank;    //格子
sem_t data;     //数据
sem_t pro_lock;    //保证生产者之间互斥的信号量
sem_t con_lock;     //保证消费者之间互斥的信号量
int ring[_SIZE_];
void* pro_run(void* arg)
{
pthread_detach(pthread_self());
static int i=0;
int id=(int)arg;
while(1)
{
sleep(1);
//      usleep(1000);
sem_wait(&blank);
sem_wait(&pro_lock);
int num=rand()%1000;
ring[i++]=num;
printf("生产者%d生产:%d,tid:%lu ",id,num,pthread_self());
i%=_SIZE_;
sem_post(&pro_lock);
sem_post(&data);
}
}
void* con_run(void* arg)
{
pthread_detach(pthread_self());
static int i=0;
int id=(int)arg;
while(1)
{
//      sleep(1);
usleep(1000);
sem_wait(&data);
sem_wait(&con_lock);
printf("消费者%d消费:%d,tid:%lu :",id,ring[i++],pthread_self());
i%=_SIZE_;
sem_post(&con_lock);
sem_post(&blank);
}
}
int main()
{
pthread_t producter,consumer,producter1,consumer1;
sem_init(&blank,0,_SIZE_);
sem_init(&data,0,0);
sem_init(&pro_lock,0,1);
sem_init(&con_lock,0,1);
int i=0;
pthread_create(&producter,NULL,pro_run,(void*)i);
pthread_create(&consumer,NULL,con_run,(void*)i);
i++;
pthread_create(&producter1,NULL,pro_run,(void*)i);
pthread_create(&consumer1,NULL,con_run,(void*)i);
sem_destroy(&blank);
sem_destroy(&data);
pthread_join(producter,NULL);
pthread_join(consumer,NULL);
return 0;
}
  semaphore(信号量)变量的类型为sem_t。

  sem_wait相当于P操作,所以,生产者每次wait的是格子信号量,sem_post相当于V操作,所以,生产者生产完之后post的是数据信号量。
  消费者wait数据,post格子。再使用两个初值为1的信号量分别为生产者与生产者之间,消费者与消费者之间加锁。我们先试试让消费者比生产者快一些(消费者相对生产者睡眠短一点),看会不会有问题。

  可见,虽然消费者比较快,但是也只能等生产者生产了它才能消费。
  再调整代码使生产者比消费者快,会出现什么现象呢?

  生产者一瞬间将缓冲队列生产满,然后等待消费者进程消费腾出格子后,它才能继续生产。这些都是我们的信号量保证的。