#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
#define NUM 10 //定义循环缓冲区大小为10
pthread_mutex_t wlock,rlock;
pthread_mutex_t rcount_lock,wcount_lock;
sem_t nowriter,wfinished;
int read_count,write_count;
int buf[]={1,2,3,4,5,6,7,8,9,10};
void* writer(void *d)
{
int data = (int)d;
if( pthread_mutex_trylock(&wlock) == 0)
{//加写锁成功
printf("writer %d get wlock\n",data);
for(int i = 0;i < 10;i++)
{
buf[i]=data;
//sleep(1);
}
pthread_mutex_unlock(&wlock);
printf("writer %d finished writing\n",data);
pthread_mutex_lock(&wcount_lock);
if(write_count == 0)//没有写者等待,唤醒读者
{
sem_post(&nowriter);
printf("writer %d is the last writer,wake up a reader\n",data);
}
else//有写者等,唤醒一个等待的写者
{
printf("writer %d detect %d writers waiting,wake up a writer\n",data,write_count);
sem_post(&wfinished);
}
pthread_mutex_unlock(&wcount_lock);
}
else//加写锁失败,当前有写者或读者运行,应加入写者等待队列
{
pthread_mutex_lock(&wcount_lock);
write_count++;//等待写者数加一
pthread_mutex_unlock(&wcount_lock);
printf("writer %d get wlock fail,block to wait,total %d waiting \n",data,write_count);
WAIT: sem_wait(&wfinished); //加入等待队列
//一个写者被唤醒,被唤醒后的写者区分于新加入写者,可能与新加入的写者竞争失败
if(pthread_mutex_trylock(&wlock) == 0)
{
printf("writer %d get wlock\n",data);
for(int i = 0;i < 10;i++)
{
buf[i]=data;
//sleep(1);
}
pthread_mutex_unlock(&wlock);
printf("writer %d waked up and finised writing\n",data);
pthread_mutex_lock(&wcount_lock);
printf("writer %d get wcount_lock\n",data);
write_count--;//等待写者数减一
if(write_count == 0)//最后一个写者唤醒等待服务的读者
{
printf("writer %d is the last writer,wake up a reader\n",data);
sem_post(&nowriter);
}
else //唤醒等待服务的写者
{
sem_post(&wfinished);
printf("writer %d detect %d writers waiting,wake up a writer\n",data,write_count);
}
pthread_mutex_unlock(&wcount_lock);
}
else
{//被新加入的写者抢占,重新加入等待队列
printf("writer %d get wlock fail,block to wait\n",data);
goto WAIT;
}
}
return NULL;
}
void* reader(void* id)
{
READER:
sem_wait(&nowriter);//等待没有写者
if(0 == pthread_mutex_trylock(&wlock))
{//第一个读者获取到写锁
printf("reader %d get wlock\n",(int)id);
read_count = 1;
pthread_mutex_lock(&wcount_lock);
if(write_count == 0)
sem_post(&nowriter);//没有写者等待服务,让第二个读者进来
pthread_mutex_unlock(&wcount_lock);
//read file
printf("reader %d read:",(int)id);
for(int i = 0;i < 10;i++)
{
printf("%d ",buf[i]);
// sleep(1);
}
printf("\n");
printf("reader %d finished reading\n",(int)id);
pthread_mutex_lock(&rcount_lock);
read_count --;
if(read_count == 0)
{
printf("reader %d is the last reader\n",(int)id);
pthread_mutex_unlock(&wlock);
pthread_mutex_lock(&wcount_lock);
if(write_count > 0)
{
sem_post(&wfinished);
printf("reader %d is the last reader,wake up 1 in %d waiting writers\n",(int)id,write_count);
}
pthread_mutex_unlock(&wcount_lock);
}
pthread_mutex_unlock(&rcount_lock);
}
else
{//失败的原因一个是有写者在写,或者已经有读者在读
printf("reader %d get wlock fail\n",(int)id);
pthread_mutex_lock(&rcount_lock);
if(read_count > 0)
{//有读者的情况
read_count++;
pthread_mutex_unlock(&rcount_lock);
pthread_mutex_lock(&wcount_lock);
if(write_count == 0)
sem_post(&nowriter);//没有写者等待服务,让更多读者进来
pthread_mutex_unlock(&wcount_lock);
//read file;
printf("reader %d:",(int)id);
for(int i = 0;i < 10;i++)
printf("%d ",buf[i]);
printf("\n");
printf("reader %d finished reading\n",(int)id);
pthread_mutex_lock(&rcount_lock);
read_count--;//读完减一
if(read_count == 0)
{
printf("reader %d is the last reder \n",(int)id);
pthread_mutex_unlock(&wlock);//最后一个读者释放写锁
pthread_mutex_lock(&wcount_lock);
if(write_count > 0)
{
sem_post(&wfinished);
printf("reader %d is the last reader,wake up 1 in %d waiting writers\n",(int)id,write_count);
}
pthread_mutex_unlock(&wcount_lock);
}
pthread_mutex_unlock(&rcount_lock);
}
else
{//有写者的情况,继续等待
goto READER;
}
}
return NULL;
}
void init()
{
read_count = write_count = 0;
pthread_mutex_init(&wlock,NULL);
pthread_mutex_init(&wcount_lock,NULL);
pthread_mutex_init(&rcount_lock,NULL);
sem_init(&wfinished,0,0);
sem_init(&nowriter,0,1);
}
int main(void)
{
init();
pthread_t r1,r2,r3,w1,w2,w3;
pthread_create(&r1,0,reader,(void*)1);
pthread_create(&r2,0,reader,(void*)2);
pthread_create(&w1,0,writer,(void*)1);
pthread_create(&w2,0,writer,(void*)2);
pthread_create(&w3,0,writer,(void*)3);
pthread_create(&r3,0,reader,(void*)3);
pthread_join(r1,NULL);
printf("main:r1 finished\n");
pthread_join(r2,NULL);
printf("main:r2 finished\n");
pthread_join(w1,NULL);
printf("main:w1 finished\n");
pthread_join(w2,NULL);
printf("main:w2 finished\n");
pthread_join(w3,NULL);
printf("main:w3 finished\n");
pthread_join(r3,NULL);
printf("main:r3 finished\n");
printf("buf data are:");
for(int i = 0;i < 10;i++)
printf("%d ",buf[i]);
printf("\n");
}