在生产者-消费者这类场景中,如果要实现同步,使用条件变量是一个很好的选择,在linux中,条件变量要结合互斥量使用。
本次我实现了一个程序,开启10个线程,其中若干是往一个共享区域写数据,其余的是从共享区域读数据,应该说是典型的生产者-消费者模式,本程序通过用户按下任意按键终止,各个线程安全退出,代码如下:
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_NUM 100
static int g_array[MAX_NUM];
volatile int g_num_gen = 0;
volatile int g_count = 0;
static int g_stop = 0;
static pthread_cond_t g_cond_w = PTHREAD_COND_INITIALIZER;
static pthread_cond_t g_cond_r = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
void *write_thread(void *arg)
{
while(!g_stop ){
pthread_mutex_lock(&g_mutex);
while( g_count == MAX_NUM && !g_stop ){/* 如果缓存区已满,则写线程等待 */
pthread_cond_wait(&g_cond_w, &g_mutex);
}
if( g_stop ){
break;
}
g_array[g_count++] = g_num_gen++;
printf("write %d count=%d tid=%lu\n", g_array[g_count-1], g_count, pthread_self() );
pthread_cond_signal(&g_cond_r);/* 通知读线程可以读了 */
pthread_mutex_unlock(&g_mutex);
usleep(1000*500);
}
pthread_mutex_unlock(&g_mutex);
pthread_cond_broadcast(&g_cond_r);
pthread_exit(NULL);
}
void *read_thread(void *arg)
{
while(!g_stop ){
pthread_mutex_lock(&g_mutex);
while( g_count == 0 && !g_stop ){/* 如果缓冲区为空,则读线程等待 */
pthread_cond_wait(&g_cond_r , &g_mutex);
}
if( g_stop ){
break;
}
printf("read %d count=%d tid=%lu\n", g_array[g_count-1], g_count, pthread_self() );
g_count--;
pthread_mutex_unlock(&g_mutex);
pthread_cond_signal(&g_cond_w);/* 通知写线程可以往缓冲区写数据了 */
usleep(1000*500);
}
pthread_mutex_unlock(&g_mutex);
pthread_cond_broadcast(&g_cond_w);
pthread_exit(NULL);
}
int main()
{
int i;
pthread_t *tid;
void *thread_result;
if ((tid = (pthread_t *)calloc(10, sizeof(pthread_t))) == NULL) {
perror("Failed to allocate space for thread IDs");
return -1;
}
/* 开启写线程 */
for(i=0; i<2; i++){
pthread_create(tid+i, NULL, write_thread, 0 );
}
/* 开启读线程 */
for(i=2; i<10; i++) {
pthread_create(tid+i, NULL, read_thread, 0 );
}
/* 由用户输入任意值,然后各个线程安全退出 */
getchar();
g_stop = 1;
for(i=0; i<10; i++ ){
pthread_join(tid[i], &thread_result);
}
free(tid);
return 0;
}
我们可以自由调节10个线程里的多少个是读线程,多少个是写线程,然后观察现象。