生产者消费者问题
这是一个非常经典的多线程题目,题目大意如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个有多个缓冲区的缓冲池,生产者将它生产的产品放入一个缓冲区中,消费者可以从缓冲区中取走产品进行消费,所有生产者和消费者都是异步方式运行的,但它们必须保持同步,即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个已经装满产品且尚未被取走的缓冲区中投放产品。
方法一,采用互斥量来实现生产者和消费者的同步。
流程图如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define NUMS 10  //表示生产,消费的次数
#define CAPACITY 5 //定义缓冲区最大值
int capacity = 0; //当前缓冲区的产品个数
pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;//互斥量
 
void *produce(void *args)
{
    int i = 0;
    for (; i < NUMS; )
    {
        pthread_mutex_lock(&mylock);//加锁
        if (capacity >= CAPACITY) //当前产品个数大于等于缓冲区最大值,则不把产品放入缓冲区。
        {
            printf("缓冲区已满,无法放入产品\n");
        } else {//将产品放入缓冲区
            ++capacity;
            printf("生产者存入一个产品, 缓冲区大小为:%d\n", capacity);
            i++;
        }
        pthread_mutex_unlock(&mylock);
    }
    return ((void *) 0);
}
 
void * consume(void *args)
{
    int i = 0;
    for (; i < NUMS; )
    {
        pthread_mutex_lock(&mylock);
        if (capacity > 0) 
        {
            --capacity;
            printf("消费者消耗一个产品,缓冲区大小为:%d\n", capacity);
            i++;
        } else
	{
           printf("缓冲区已空,无法消耗产品\n");
        }
        pthread_mutex_unlock(&mylock);
    }
    return ((void *) 0);
}
 
int main(int argc, char** argv) {
 
    int err;
    pthread_t produce_tid, consume_tid;
    void *ret;
    err = pthread_create(&produce_tid, NULL, produce, NULL);//创建线程
    if (err != 0) 
    {
        printf("线程创建失败:%s\n", strerror(err));
        exit(-1);
    }
    err = pthread_create(&consume_tid, NULL, consume, NULL);
    if (err != 0)
    {
        printf("线程创建失败:%s\n", strerror(err));
        exit(-1);
    }
    err = pthread_join(produce_tid, &ret);//主线程等到子线程退出
    if (err != 0) 
    {
        printf("生产着线程分解失败:%s\n", strerror(err));
        exit(-1);
    }
    err = pthread_join(consume_tid, &ret);
    if (err != 0)
    {
        printf("消费者线程分解失败:%s\n", strerror(err));
        exit(-1);
    }
    return (EXIT_SUCCESS);
}

执行结果:

结果满足题意。但是这存在一个问题,极端情况下,生产者每次都加锁成功,那缓冲区会满,产品无法放入缓冲区。消费者会被饿死,因为他一直无法获得互斥量。方法二,解决了导致某一方饿死的可能性。
update:
在第一种方法中,当缓冲区满时,让生产者睡眠;当缓冲区空,让消费者睡眠。这样也能解决某一方老是加锁成功。
方法二:采用两个互斥量来完成
流程图如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
 
#define NUMS 10  //表示生产,消费的次数
#define CAPACITY 5 //定义缓冲区最大值
 
 
int capacity = 0; //当前缓冲区的产品个数
pthread_mutex_t mylockA=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mylockB=PTHREAD_MUTEX_INITIALIZER;
 
void *produce(void *args)
{
    int i = 0,err;
    for (; i < NUMS; )
    {
        pthread_mutex_lock(&mylockA);//加锁
        if (capacity >= CAPACITY) //当前产品个数大于等于缓冲区最大值,则不把产品放入缓冲区。
        {
            printf("缓冲区已满,无法放入产品\n");
        } else {//将产品放入缓冲区
            ++capacity;
            printf("生产者存入一个产品, 产品个数:%d\n", capacity);
            i++;
        }
        err=pthread_mutex_unlock(&mylockB);
    }
    return ((void *) 0);
}
 
void * consume(void *args)
{
    int i = 0;
    for (; i < NUMS; )
    {
        pthread_mutex_lock(&mylockB);
        if (capacity > 0) 
        {
            --capacity;
            printf("消费者消耗一个产品,产品个数:%d\n", capacity);
            i++;
        } else
	{
           printf("缓冲区已空,无法消耗产品\n");
        }
        pthread_mutex_unlock(&mylockA);
    }
    return ((void *) 0);
}
 
int main(int argc, char** argv) {
 
    int err;
    pthread_t produce_tid, consume_tid;
    void *ret;
    if(capacity==0)
        pthread_mutex_lock(&mylockB);
    else
        if(capacity==CAPACITY)
            pthread_mutex_lock(&mylockA);
    err = pthread_create(&produce_tid, NULL, produce, NULL);//创建线程
    if (err != 0) 
    {
        printf("线程创建失败:%s\n", strerror(err));
        exit(-1);
    }
    err = pthread_create(&consume_tid, NULL, consume, NULL);
    if (err != 0)
    {
        printf("线程创建失败:%s\n", strerror(err));
        exit(-1);
    }
    err = pthread_join(produce_tid, &ret);//主线程等到子线程退出
    if (err != 0) 
    {
        printf("生产着线程分解失败:%s\n", strerror(err));
        exit(-1);
    }
    err = pthread_join(consume_tid, &ret);
    if (err != 0)
    {
        printf("消费者线程分解失败:%s\n", strerror(err));
        exit(-1);
    }
    return (EXIT_SUCCESS);
}

执行结果