生产者-消费者是很有意思的一种算法。它的存在主要是两个目的,第一就是满足生产者对资源的不断创造;第二就是满足消费者对资源的不断索取。当然,因为空间是有限的,所以资源既不能无限存储,也不能无限索取。
生产者-消费者问题是一个经典的进程同步问题,该问题最早由Dijkstra提出,用以演示他提出的信号量机制。在同一个进程地址空间内执行的两个线程。生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。
以下linux程序展示的是一个生产者和一个消费者共享一个NBUFF大小的缓冲区进行同步的演示
- #include<stdio.h>
- #include<string.h>
- #include<pthread.h>
- #include<unistd.h>
- #include<semaphore.h>
- #include<fcntl.h>
- #include<sys/stat.h>
- #define NBUFF 10 // 缓冲区大小
- #define SEM_MUTEX "mutex"
- #define SEM_NEMPTY "nempty"
- #define SEM_NSTORED "nstored"
- static int nitems = NBUFF;
- struct _shared
- {
- int buff[ NBUFF ]; // 缓冲区大小
- sem_t* mutex; // 访问缓冲区的互斥锁
- sem_t* nempty; // 当前空闲的缓冲区个数
- sem_t* nstored; // 当前缓冲区可用个数
- } shared; // 线程共享量
- void* producer( void* );
- void* consumer( void* );
- int main( int argc, char** argv )
- {
- pthread_t tid_producer, tid_consumer;
- memset( shared.buff, 0, sizeof( shared.buff ) );
- shared.mutex = sem_open( SEM_MUTEX, O_CREAT | O_EXCL, 0644, 1 );
- shared.nempty = sem_open( SEM_NEMPTY, O_CREAT | O_EXCL, 0644, NBUFF );
- shared.nstored = sem_open( SEM_NSTORED, O_CREAT | O_EXCL, 0644, 0 );
- pthread_setconcurrency( 2 );
- // create producer and consumer
- pthread_create( &tid_producer, NULL, producer, NULL );
- pthread_create( &tid_consumer, NULL, consumer, NULL );
- // wait for two threads
- pthread_join( tid_producer, NULL );
- pthread_join( tid_consumer, NULL );
- // remove semaphores
- sem_unlink( SEM_MUTEX );
- sem_unlink( SEM_NEMPTY );
- sem_unlink( SEM_NSTORED );
- return 0;
- }
- void* producer( void* arg )
- {
- int i ;
- for ( i = 0; i < nitems; i++ )
- {
- sem_wait( shared.nempty ); // P( nempty )
- sem_wait( shared.mutex ); // P( mutex )
- shared.buff[ i % NBUFF ] = i;
- printf( "producer: %d\n", shared.buff[ i % NBUFF ] );
- sem_post( shared.mutex ); // V( mutex )
- sem_post( shared.nstored ); // V( nstored )
- sleep( 1 ); // 暂停,唤醒consumer
- }
- return ( void* )0;
- }
- void* consumer( void* arg )
- {
- int i;
- for ( i = 0; i < nitems; i++ )
- {
- sem_wait( shared.nstored ); // P( nstored )
- sem_wait( shared.mutex ); // P( mutex )
- printf( "consumer: buff[%d] = %d\n", i, shared.buff[ i % NBUFF ] );
- sem_post( shared.mutex ); // V( mutex )
- sem_post( shared.nempty ); // V( empty )
- sleep( 2 ); // 暂停,唤醒producer
- }
- return ( void* )0;
- }
#include<stdio.h>
#include<string.h>
#include<pthread.h>
#include<unistd.h>
#include<semaphore.h>
#include<fcntl.h>
#include<sys/stat.h>
#define NBUFF 10 // 缓冲区大小
#define SEM_MUTEX "mutex"
#define SEM_NEMPTY "nempty"
#define SEM_NSTORED "nstored"
static int nitems = NBUFF;
struct _shared
{
int buff[ NBUFF ]; // 缓冲区大小
sem_t* mutex; // 访问缓冲区的互斥锁
sem_t* nempty; // 当前空闲的缓冲区个数
sem_t* nstored; // 当前缓冲区可用个数
} shared; // 线程共享量
void* producer( void* );
void* consumer( void* );
int main( int argc, char** argv )
{
pthread_t tid_producer, tid_consumer;
memset( shared.buff, 0, sizeof( shared.buff ) );
shared.mutex = sem_open( SEM_MUTEX, O_CREAT | O_EXCL, 0644, 1 );
shared.nempty = sem_open( SEM_NEMPTY, O_CREAT | O_EXCL, 0644, NBUFF );
shared.nstored = sem_open( SEM_NSTORED, O_CREAT | O_EXCL, 0644, 0 );
pthread_setconcurrency( 2 );
// create producer and consumer
pthread_create( &tid_producer, NULL, producer, NULL );
pthread_create( &tid_consumer, NULL, consumer, NULL );
// wait for two threads
pthread_join( tid_producer, NULL );
pthread_join( tid_consumer, NULL );
// remove semaphores
sem_unlink( SEM_MUTEX );
sem_unlink( SEM_NEMPTY );
sem_unlink( SEM_NSTORED );
return 0;
}
void* producer( void* arg )
{
int i ;
for ( i = 0; i < nitems; i++ )
{
sem_wait( shared.nempty ); // P( nempty )
sem_wait( shared.mutex ); // P( mutex )
shared.buff[ i % NBUFF ] = i;
printf( "producer: %d\n", shared.buff[ i % NBUFF ] );
sem_post( shared.mutex ); // V( mutex )
sem_post( shared.nstored ); // V( nstored )
sleep( 1 ); // 暂停,唤醒consumer
}
return ( void* )0;
}
void* consumer( void* arg )
{
int i;
for ( i = 0; i < nitems; i++ )
{
sem_wait( shared.nstored ); // P( nstored )
sem_wait( shared.mutex ); // P( mutex )
printf( "consumer: buff[%d] = %d\n", i, shared.buff[ i % NBUFF ] );
sem_post( shared.mutex ); // V( mutex )
sem_post( shared.nempty ); // V( empty )
sleep( 2 ); // 暂停,唤醒producer
}
return ( void* )0;
}
// 编译
- kennie@cbib:~/pthreadDIR$ g++ -lpthread -o producer_consumer.out producer_consumer.cpp
kennie@cbib:~/pthreadDIR$ g++ -lpthread -o producer_consumer.out producer_consumer.cpp
// 运行结果
- producer: 0
- consumer: buff[0] = 0
- producer: 1
- consumer: buff[1] = 1
- producer: 2
- producer: 3
- consumer: buff[2] = 2
- producer: 4
- producer: 5
- consumer: buff[3] = 3
- producer: 6
- producer: 7
- consumer: buff[4] = 4
- producer: 8
- producer: 9
- consumer: buff[5] = 5
- consumer: buff[6] = 6
- consumer: buff[7] = 7
- consumer: buff[8] = 8
- consumer: buff[9] = 9