Linux线程中写过生产者消费者模型,这次研究读者写者模型。
读者写者模型遵循的规则
读者-写者模型同样遵循321规则:
- 写-写互斥,即不能有两个写者同时进行写操作。
- 读-写互斥,即不能同时有一个线程在读,而另一个线程在写。
- 读-读允许,读者和读者之间没有关系,即可以有一个或多个读者同时读。
读优先
如果一个读者申请进行读操作时已有另一个读者正在进行读操作,则该读者可直接开始读操作。而此时写者正在被阻塞,只有所有的读者都读完,写者才会被唤醒。
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <iostream>
using namespace std;
struct data
{
string str;
};
data shareData;
sem_t mutex_readCount, mutex_write;
int readCount;
void* Reader(void* param)
{
printf("线程 %ud: 正在等待读\n",pthread_self());
int readWait = rand()%5;
sleep(readWait);
sem_wait(&mutex_readCount);
readCount++;
if(readCount == 1)
{
sem_wait(&mutex_write);
}
sem_post(&mutex_readCount);
printf("线程 %ud: 开始进行读\n", pthread_self());
cout<<"读者读出数据:"<<shareData.str<<endl;;
printf("线程 %ud: 读取完毕\n", pthread_self());
sem_wait(&mutex_readCount);
readCount--;
if(readCount == 0)
{
sem_post(&mutex_write);
}
sem_post(&mutex_readCount);
pthread_exit(0);
}
void* Writer(void* param)
{
printf("线程 %ud: 正在等待写\n",pthread_self());
int writeWait = rand()%5;
sleep(writeWait);
string& writeStr= ((data*)param)->str;
sem_wait(&mutex_write);
printf("线程 %ud: 开始写入:%s\n",pthread_self(),writeStr.c_str());
shareData.str=writeStr;
printf("线程 %ud: 写完\n",pthread_self());
sem_post(&mutex_write);
pthread_exit(0);
}
int main()
{
srand((unsigned)time(NULL));
pthread_t tid1;
pthread_t tid2;
pthread_t tid3;
pthread_t tid4;
pthread_t tid5;
readCount=0;
shareData.str="默认值";
sem_init(&mutex_readCount, 0, 1);
sem_init(&mutex_write, 0, 1);
readCount = 0;
pthread_create(&tid2, NULL, Reader, NULL);
data w1;
w1.str="abc";
pthread_create(&tid1, NULL, Writer, (void*)&w1);
pthread_create(&tid4, NULL, Reader, NULL);
pthread_create(&tid5, NULL, Reader, NULL);
data w2;
w2.str="1234";
pthread_create(&tid3, NULL, Writer, (void*)&w2);
sem_destroy(&mutex_readCount);
sem_destroy(&mutex_write);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);
pthread_join(tid4,NULL);
pthread_join(tid5,NULL);
return 0;
}
写者优先
如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。
换句话说,如果一个读者A申请进行读操作,并且写者想进行写操作,此时A会与写者竞争锁,如果写者竞争成功则写者先写,后续来的写者由于多线程原因会处于等待状态(等前一个写者写完),只有当等待状态的写者数量为0时,读者A才可以进行读。 如果读者A竞争成功则A先读,后续的读者B仍然要与写者竞争。
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <iostream>
using namespace std;
struct data
{
string str;
};
data shareData;
sem_t rwMutex, mutex_writeCount, mutex_readCount, mutex_write;
int writeCount, readCount;
sem_t mutex;
void* Reader(void* param)
{
printf("线程 %ud: 正在等待读\n",pthread_self());
int readWait = rand()%5;
sleep(readWait);
sem_wait(&mutex);
sem_wait(&rwMutex);
sem_wait(&mutex_readCount);
readCount++;
readWait++;
if(readCount == 1)
{
sem_wait(&mutex_write);
}
sem_post(&mutex_readCount);
sem_post(&rwMutex);
sem_post(&mutex);
printf("线程 %ud: 开始进行读\n", pthread_self());
cout<<"读者读出数据:"<<shareData.str<<endl;;
printf("线程 %ud: 读取完毕\n", pthread_self());
sem_wait(&mutex_readCount);
readCount--;
if(readCount == 0)
{
sem_post(&mutex_write);
}
sem_post(&mutex_readCount);
pthread_exit(0);
}
void* Writer(void* param)
{
printf("线程 %ud: 正在等待写\n",pthread_self());
int writeWait = rand()%5;
sleep(writeWait);
string& writeStr= ((data*)param)->str;
sem_wait(&mutex_writeCount);
writeCount++;
writeWait++;
if(writeCount == 1)
{
sem_wait(&rwMutex);
}
sem_post(&mutex_writeCount);
sem_wait(&mutex_write);
printf("线程 %ud: 开始写入:%s\n",pthread_self(),writeStr.c_str());
shareData.str=writeStr;
printf("线程 %ud: 写完\n",pthread_self());
sem_post(&mutex_write);
sem_wait(&mutex_writeCount);
writeCount--;
if(writeCount == 0)
{
sem_post(&rwMutex);
}
sem_post(&mutex_writeCount);
pthread_exit(0);
}
int main()
{
srand((unsigned)time(NULL));
pthread_t tid1;
pthread_t tid2;
pthread_t tid3;
pthread_t tid4;
pthread_t tid5;
writeCount=readCount=0;
shareData.str="默认值";
sem_init(&rwMutex, 0, 1);
sem_init(&mutex_writeCount, 0, 1);
sem_init(&mutex_readCount, 0, 1);
sem_init(&mutex_write, 0, 1);
sem_init(&mutex, 0, 1);
pthread_create(&tid2, NULL, Reader, NULL);
data w1;
w1.str="abc";
pthread_create(&tid1, NULL, Writer, (void*)&w1);
pthread_create(&tid4, NULL, Reader, NULL);
pthread_create(&tid5, NULL, Reader, NULL);
data w2;
w2.str="1234";
pthread_create(&tid3, NULL, Writer, (void*)&w2);
sem_destroy(&rwMutex);
sem_destroy(&mutex_writeCount);
sem_destroy(&mutex_readCount);
sem_destroy(&mutex_write);
sem_destroy(&mutex);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);
pthread_join(tid4,NULL);
pthread_join(tid5,NULL);
return 0;
}
|