生产者消费者模型和读者写者模型使我们常见的关于线程同步与互斥有关的模型,它们的实现对理解线程同步互斥有很好的帮助。
生产者消费者模型
如上图,生产者生产一个产品并放到仓库中,消费者从仓库中取产品,生产和消费者两个动作是互斥的,而生产者和生产者,消费者和消费者之间是同步的。
具体代码实现如下:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#define CONSUMERS 2
#define PRODUCERS 2
typedef struct msg{
struct msg* next;
int num;
}msg;
struct msg* head = NULL;
pthread_cond_t cond;
pthread_mutex_t mutex;
pthread_t threads[CONSUMERS + PRODUCERS];
void* consumer(void* p){
free(p);
for(;;){
}
int num = *(int *)p;
free(p);
struct msg* mp;
for(;;){
pthread_mutex_lock(&mutex);
while(head == NULL){
printf("%d begin wait a condition\n", num);
pthread_cond_wait(&cond, &mutex);
}
printf("%d end wait a condition\n", num);
printf("%d begin consume product\n", num);
mp = head;
head = mp -> next;
pthread_mutex_unlock(&mutex);
printf("consume %d\n", mp -> num);
free(mp);
printf("%d end consume produt\n", num);
sleep(rand()%5);
}
}
void* producer(void* p){
int num = *(int*) p ;
free(p);
struct msg* mp;
for(;;){
printf("%d begin produce product\n", num);
mp = (struct msg*)malloc(sizeof(struct msg));
mp -> num = rand()%100 + 1;
printf("produce %d\n", num);
pthread_mutex_lock(&mutex);
mp -> next = head;
head = mp;
printf("%d end produce product\n", num);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
sleep(rand()%5);
}
}
int main(){
srand(time(NULL));
pthread_cond_init(&cond, NULL);
pthread_mutex_init(&mutex, NULL);
int i = 0;
for(; i < CONSUMERS; ++i){
int* p = (int*)malloc(sizeof(int));
*p = i;
pthread_create(&threads[i], NULL, consumer, (void*)p);
}
i = 0;
for(; i < PRODUCERS; ++i){
int* p = (int*)malloc(sizeof(int));
*p = i;
pthread_create(&threads[CONSUMERS + i], NULL, producer, (void*)p);
}
for(i = 0; i < CONSUMERS + PRODUCERS; ++i){
pthread_join(threads[i], NULL);
}
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
return 0;
}
上面的那种模型知识生产者消费者模型的一种,当仓库不是刚才那种队列,而是环形队列的时候,就需要用到POSXI信号量,这个在前面写的线程同步和互斥博客里面有,POSXI信号量
读者写者模型
读者写者模型是为了处理改写少,读操作多的这种情况,随之而生的还有读写锁
读写锁的行为如下图:
写锁优先级高
读写锁接口:
初始化:
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_relockattr_t *restrict attr);
销毁:
int pthread_rwlock_destroy(pthread_relock_t *relock);
加锁和解锁:
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
读者写者模型代码实现:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
//创建5个读者线程,3个写者线程
int counter;
pthread_rwlock_t rwlock;
void* route_write(void* arg){
int t = 0;
int i = *(int*)arg;
free(arg);
while(1){
t = counter;
pthread_rwlock_wrlock(&rwlock);
printf("write_thread:%d tid:%lu: oldd_counter:%d new_counter:%d\n",i, pthread_self(), t, ++counter);
pthread_rwlock_unlock(&rwlock);
sleep(5);
}
}
void* route_read(void* arg){
int i = *(int*)arg;
free(arg);
while(1){
pthread_rwlock_rdlock(&rwlock);
printf("thread_read:%d tid:%lu counter data is:%d\n", i, pthread_self(), counter);
pthread_rwlock_unlock(&rwlock);
sleep(1);
}
}
int main(){
int i;
pthread_t tid[8];
pthread_rwlock_init(&rwlock, NULL);
for(i = 0; i < 3; ++i){
int *p = (int*)malloc(sizeof(int));
*p = i;
pthread_create(&tid[i], NULL, route_write, (void*)p);
}
for(i = 0; i < 5; ++i){
int *p = (int*)malloc(sizeof(int));
*p = i;
pthread_create(&tid[i+3], NULL, route_read, (void*)p);
}
for(i = 0; i < 8; ++i){
pthread_join(tid[i], NULL);
}
pthread_rwlock_destroy(&rwlock);
return 0;
}