三种关系:互斥,同步,互斥和同步
两类角色:生产者,消费者(线程)
一个交易场所:生产者消费者共享的区域
卖苹果的模型
- dish上面只有一个苹果
- 买家必须要等卖家把苹果放到dish上才可以去买苹果。
- 卖家必须等待买家把苹果买走才可以生产苹果
- pthread_mutex_lock(&mutex); 和pthread_mutex_unlock(&mutex); 成对出现,里面的操作为一个原子操作
- pthread_cond_wait(&empty,&mutex);内部有一个加锁解锁操作
- 过程详解
- 苹果为0
- 初始化时苹果为0,买家在pthread_cond_wait(&empty,&mutex); 开始等待,卖家不进入while循环,生产苹果后发出pthread_cond_signal(&empty);让正在因dish上苹果为0的买家停止等待pthread_cond_wait(&empty,&mutex);
- 苹果为1
- 当一个卖家进入pthread_mutex_lock(&mutex); 但是发现苹果为1时,就在while循环处等待pthread_cond_wait(&empty,&mutex);,直到买家发出信号 pthread_cond_signal(&full);卖家停止等待,此时苹果为0,跳出while循环,开始生产苹果。生产苹果后发出pthread_cond_signal(&empty);让正在因dish上苹果为0的买家停止等待pthread_cond_wait(&empty,&mutex); 这样这个过程就结束了
*
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>int dish = 0;
pthread_cond_t full;
pthread_cond_t empty;
pthread_mutex_t mutex;void * consumer(void * arg)
{int id = (int)arg;while(1){pthread_mutex_lock(&mutex);//上锁while(dish == 0){//买家发现没有苹果开始等待pthread_cond_wait(&empty,&mutex);}usleep(100000);dish = 0;printf("consumer %d get an apple!!\n", id);//给卖家发送信号pthread_cond_signal(&full);pthread_mutex_unlock(&mutex);//解锁}return NULL;
}void * product(void *arg)
{int id = (int)arg;while(1){pthread_mutex_lock(&mutex); while(dish == 1){pthread_cond_wait(&full,&mutex);}dish =1;printf("producer %d put an apple!!\n", id); pthread_cond_signal(&empty);pthread_mutex_unlock(&mutex);}return NULL;
}int main()
{pthread_t tid;int set ;//初始化pthread_cond_init(&full,NULL);pthread_cond_init(&empty,NULL);pthread_mutex_init(&mutex,NULL);//四个卖家生产苹果for(int i = 0;i<4;i++){pthread_create(&tid,NULL,product,(void *)i);}//四个买家买苹果for(int i = 0;i<4;i++){pthread_create(&tid,NULL,consumer,(void *)i);}//等待thread标识的线程终止,防止僵尸进程产生pthread_join(tid,NULL);//销毁所有资源pthread_cond_destroy(&full);pthread_cond_destroy(&empty);pthread_mutex_destroy(&mutex);
}
如果对于互斥量含义尚不清楚,建议阅读Linux/UNIX系统编程手册
pthread_mutex_t
pthread_mutex_init
pthread_mutex_lock
pthread_mutex_unlock
pthread_mutex_destroy
模型采取Linux/UNIX系统编程手册
这个模型很好,也把概念讲清楚了,加了中文注释
生产者
s = pthread_mutex_lock(&mtx);
if (s != 0)errExitEN(s, "pthread_mutex_lock");avail++; /*这是一个原子操作 */s = pthread_mutex_unlock(&mtx);
if (s != 0)errExitEN(s, "pthread_mutex_unlock");s = pthread_cond_signal(&cond); /* 唤醒消费者 */
if (s != 0)errExitEN(s, "pthread_cond_signal");
消费者
s = pthread_mutex_lock(&mtx);
if (s != 0)errExitEN(s, "pthread_mutex_lock");while (avail == 0){ s = pthread_cond_wait(&cond, &mtx);if (s != 0)errExitEN(s, "pthread_cond_wait");
}
完整代码
#include <time.h>
#include <pthread.h>
#include "tlpi_hdr.h"static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;static int avail = 0;static void *
threadFunc(void *arg)
{int cnt = atoi((char *) arg);int s, j;for (j = 0; j < cnt; j++) {sleep(1);/* Code to produce a unit omitted */s = pthread_mutex_lock(&mtx);if (s != 0)errExitEN(s, "pthread_mutex_lock");avail++; /* Let consumer know another unit is available */s = pthread_mutex_unlock(&mtx);if (s != 0)errExitEN(s, "pthread_mutex_unlock");s = pthread_cond_signal(&cond); /* Wake sleeping consumer */if (s != 0)errExitEN(s, "pthread_cond_signal");}return NULL;
}int
main(int argc, char *argv[])
{pthread_t tid;int s, j;int totRequired; /* Total number of units that all threadswill produce */int numConsumed; /* Total units so far consumed */Boolean done;time_t t;t = time(NULL);/* Create all threads */totRequired = 0;for (j = 1; j < argc; j++) {totRequired += atoi(argv[j]);s = pthread_create(&tid, NULL, threadFunc, argv[j]);if (s != 0)errExitEN(s, "pthread_create");}/* Loop to consume available units */numConsumed = 0;done = FALSE;for (;;) {s = pthread_mutex_lock(&mtx);if (s != 0)errExitEN(s, "pthread_mutex_lock");while (avail == 0) { /* Wait for something to consume */s = pthread_cond_wait(&cond, &mtx);if (s != 0)errExitEN(s, "pthread_cond_wait");}/* At this point, 'mtx' is locked... */while (avail > 0) { /* Consume all available units *//* Do something with produced unit */numConsumed ++;avail--;printf("T=%ld: numConsumed=%d\n", (long) (time(NULL) - t),numConsumed);done = numConsumed >= totRequired;}s = pthread_mutex_unlock(&mtx);if (s != 0)errExitEN(s, "pthread_mutex_unlock");if (done)break;/* Perhaps do other work here that does not require mutex lock */}exit(EXIT_SUCCESS);
}