使用条件变量信号量实现生产者消费者实例
贴出实例前首先介绍多线程编程中需要使用到的几个系统函数。
1 2 | int pthread_mutex_lock(pthread_mutex_t *mutex) int pthread_mutex_unlock(pthread_mutex_t *mutex) |
1、将互斥量锁住,获取不到时将线程阻塞住,按照锁的特性进行相应等待响应动作,当获取到互斥锁时恢复线程。
1 2 | int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex) int pthread_cond_signal(pthread_cond_t *cond) |
2、条件变量,条件变量的使用是利用全局变量互斥量来保驾护航,也就是说在调用条件变量等待前需要先获取到互斥量,保证条件变量的调用等待有先后顺序,调用者把线程放到等待条件的线程列表上,然后释放互斥量解锁进入阻塞状态等待另外进程唤醒,这两个动作之间是原子性的,保证这个过程中不会错过任何唤醒信号。
1 2 | int sem_wait(sem_t *sem) int sem_post(sem_t *sem) |
3、信号量,原子性减少、增加。
条件变量版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | #include #include #define BUFFER_SIZE 4 #define OVER (-1) struct producers{ //定义生产者条件变量的结构 int buffer[BUFFER_SIZE];//定义缓冲区 pthread_mutex_t lock;//定义访问缓冲区的互斥锁 int readpos,writepos;//读写位置指针 pthread_cond_t notempty;//缓冲区中有数据时的标记 pthread_cond_t notfull;//缓冲区未满的标记 }; //初始化缓冲区 void init(struct producers *b){ pthread_mutex_init(&b->lock,NULL); pthread_cond_init(&b->notempty,NULL); pthread_cond_init(&b->notfull,NULL); b->readpos = 0; b->writepos = 0; } //在缓冲区中存放一个整数 void put(struct producers *b,int data){ pthread_mutex_lock(&b->lock); //当缓冲区为满时等待 while((b->writepos+1)%BUFFER_SIZE==b->readpos){ pthread_cond_wait(&b->notfull,&b->lock); } b->buffer[b->writepos] = data; b->writepos++; if(b->writepos>=BUFFER_SIZE) b->writepos = 0; //发送当前缓冲区中有数据的信号 pthread_cond_signal(&b->notempty); pthread_mutex_unlock(&b->lock); } //从缓冲区中读数据并将数据从缓冲区中移走 int get(struct producers *b){ int data; pthread_mutex_lock(&b->lock); while(b->writepos==b->readpos){ pthread_cond_wait(&b->notempty,&b->lock); } //从缓冲区读数据,并将指针前移 data = b->buffer[b->readpos]; b->readpos++; if(b->readpos>=BUFFER_SIZE) b->readpos = 0; //发送当前缓冲区未满的信号 pthread_cond_signal(&b->notfull); pthread_mutex_unlock(&b->lock); return data; } struct producers buffer; void *producer(void *data){ int n; for(n = 0;n<10;n++){ printf("Producer:%d-->\n",n); put(&buffer,n); } put(&buffer,OVER); return NULL; } void *consumer(void *data){ int d; while(1){ d = get(&buffer); if(d==OVER){ break; } printf("Consumer:-->%d\n",d); } return NULL; } int main(){ pthread_t tha,thb; void *retval; init(&buffer); pthread_create(&thb,NULL,consumer,0); pthread_create(&tha,NULL,producer,0); pthread_join(tha,&retval); pthread_join(thb,&retval); return 0; } |
信号量例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | #include #include #include #define BUFFER_SIZE 4 #define OVER (-1) struct producers{ int buffer[BUFFER_SIZE]; int readpos,writepos;//读写位置 sem_t sem_read;//可读信号量 sem_t sem_write;//可写信号量 }; void init(struct producers *b){ sem_init(&b->sem_write,0,BUFFER_SIZE-1); sem_init(&b->sem_read,0,0); b->readpos = 0; b->writepos = 0; } void put(struct producers *b, int data){ sem_wait(&b->sem_write); b->buffer[b->writepos] = data; b->writepos++; if(b->writepos>=BUFFER_SIZE) b->writepos = 0; sem_post(&b->sem_read); } int get(struct producers *b){ int data; sem_wait(&b->sem_read); data = b->buffer[b->readpos]; b->readpos++; if(b->readpos >= BUFFER_SIZE) b->readpos = 0; sem_post(&b->sem_write); return data; } struct producers buffer; void *producer(void *data){ int n; for(n = 0;n <10; n++){ printf("Producer : %d-->\n",n); put(&buffer, n); } put(&buffer,OVER); return NULL; } void *consumer(void *data){ int d; while(1){ d = get(&buffer); if(d == OVER) break; printf("Consumer: --> %d\n",d); } return NULL; } int main(){ pthread_t tha,thb; void *retval; init(&buffer); pthread_create(&tha, NULL, producer, 0); pthread_create(&thb, NULL, consumer, 0); pthread_join(tha, &retval); pthread_join(thb, &retval); return 0; } |
多线程资源回收学习–pthread_cleanup_push/pop 线程取消(pthread_cancel)(转)