多线程通信之读者、写者问题
读、写问题是另一个非常出名的同步问题,常常用来模拟数据库的数据查询和数据修改两种情况问题。也即,
一个数据库允许有多个访问者同时对其进行数据访问,但是对于数据的修改只能有一个。那么如何来控制这种访问多个,而修改只能一个的数据操作方式?这也涉及到线程间通信和同步问题。
数据库中存在的情况为:
读者、读者可以同时存在;
读者、写者不能同时存在,如果读者在前,则写者等待;否则所有读者等待;
写者、写者不能同时存在,先到先做,后到等待。
假设当前数据库新来了一个访问者,那么它可能的状况为以下几种:
当前数据库还没有读者、写者,那么新读者可以读;
有写者在等待,但其他读者正在读,那么新读者也可以读;
有写者在写,那么新读者等待;
假设当前数据库新来了一个写者,那么它可能的状况为以下几种:
当前数据库没有读者、写者,那么新写者可以写;
有读者在读,那新写者等待;
有写者在写,则新写者等待。
伪代码
wait (num),num是目标参数,wait的作用是使其(信息量)减一。如果信息量>=0,则该进程继续执行;否则该进程置为等待状态,排入等待队列。
signal (num),num是目标参数,signal的作用是使其(信息量)加一。 如果信息量>0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。
semaphore rmutex = 1,wmutex;//互斥信号量,解决读者和写者之间的互斥信号量wmutex,为readerCount设置信号量rmutex;
int readerCount = 0;//读者数量readerCount全局变量(共享资源)
//编写读者进程的操作
点击查看代码
void Reader(){
do{
wait(rmutex);//为readerCount设置的信号量
if(readerCount == 0)//如果现在没有读者在读,就要开启读者-写者互斥锁,防止写者抢占了资源
wait(wmutex);//解决读者写者互斥问题
readerCount++;//读者数量加一
signal(rmutex);//释放读者数量互斥资源
//...
//perform read operation;
//操作一般要长时间,sleep(毫秒数)
//...
wait(rmutex);
readercount--;
if(readerCount == 0)
signal(wmutex);//
signal(rmutex);//如果没有读者在读了,就允许写者写了,这样就可以把互斥锁打开了。
}while(TRUe);
}
//编写写者进程
void Writer(){//写者与任何进程互斥,简单的P、V操作即可实现
do{
wait(wmutex);//读者写者互斥冲突信号量
//...
//perform write operation
//操作一般要长时间,sleep(毫秒数)模拟
//...
signal(wmutex);
}while(TRUE);
}
void main(){
cobegin()
Reader();
Writer();
coend
}
伪代码描述
使用线程同步实现上述算法
对于线程,有以下流程:定义--创建初始化-线程运行函数--线程退出
对于信号量,有以下流程:定义--创建初始化--信号量wait和signal--信号量销毁
信号量为什么要销毁:因为要防止资源泄密,信号量是用来解决进程互斥资源共享冲突的,所以信号量的值可以表示当前某些进程之间共享资
源的使用情况,若不销毁,随后无意中改变了信号量的值,可能会导致进程间死锁现象。
对于一个进程,可以在该进程中创建多个线程,多个线程之间共享资源,资源申请就存在互斥关系,需要有锁的概念,信号量可以实现锁。
对于写者线程pthread_t writerTidp;定义了了该线程writerTidp,pthread_create(&writerTidp,NULL,writerThread,NULL) 创建了该线程,并指明线程函数入口是writerThread,该函数入口声明如下static void *writerThread(void *arg);
代码实现
点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
sem_t rmutex,wmutex;
static void *readerThread(void *arg);
static void *reader3Thread(void *arg);
static void *reader2Thread(void *arg);
static void *writerThread(void *arg);
int readcount = 0;
int n = 0;
int nowLen = 1;
char contentArticle[10][100];
int main(){
pthread_t readerTidp,writerTidp,reader3Tidp,reader2Tidp;
void *retval;
if(sem_init(&rmutex,0,1)==-1||sem_init(&wmutex,0,1)==-1){
printf("sem_init error\n");
return -1;
}//init semaphore
if(pthread_create(&readerTidp,NULL,readerThread,NULL) !=0||pthread_create(&writerTidp,NULL,writerThread,NULL) !=0||pthread_create(&reader3Tidp,NULL,reader3Thread,NULL) !=0||pthread_create(&reader2Tidp,NULL,reader2Thread,NULL) !=0){
printf("pthread_create error\n");
return -2;
}//init pthread
pthread_join(readerTidp,&retval);
pthread_join(reader3Tidp,&retval);
pthread_join(reader2Tidp,&retval);
pthread_join(writerTidp,&retval);
sem_destroy(&rmutex);
sem_destroy(&wmutex);
return 0;
}
static void *readerThread(void *arg){
for(int i = 0;i < 10;i++)
{
sem_wait(&rmutex);
if(readcount == 0)sem_wait(&wmutex);
readcount = readcount+1;
sem_post(&rmutex);
//read operatiom
printf("\n\nI'm reader first Reader thread :...the global variable n equals to %d\n",n);
for(int j = 0;j < nowLen-1;j++)
{
for(int k = 0;k < 26;k++)
printf("%c",contentArticle[j][k]);
printf("\n");
}
printf("now the count 0f reader is %d\n",readcount);
printf("now the length 0f content is %d\n",nowLen-1);
sleep(5);
sem_wait(&rmutex);
readcount = readcount-1;
if(readcount == 0)sem_post(&wmutex);
sem_post(&rmutex);
sleep(1);
}
}
static void *reader3Thread(void *arg){
for(int i = 0;i < 10;i++)
{
sem_wait(&rmutex);
if(readcount == 0)sem_wait(&wmutex);
readcount = readcount+1;
sem_post(&rmutex);
//read operatiom
printf("\n\nI'm reader third Reader thread :...the global variable n equals to %d\n",n);
for(int j = 0;j < nowLen-1;j++)
{
for(int k = 0;k < 26;k++)
printf("%c",contentArticle[j][k]);
printf("\n");
}
printf("now the count 0f reader is %d\n",readcount);
printf("now the length 0f content is %d\n",nowLen-1);
sleep(5);
sem_wait(&rmutex);
readcount = readcount-1;
if(readcount == 0)sem_post(&wmutex);
sem_post(&rmutex);
sleep(8);
}
}
static void *reader2Thread(void *arg){
for(int i = 0;i < 10;i++)
{
sem_wait(&rmutex);
if(readcount == 0)sem_wait(&wmutex);
readcount = readcount+1;
sem_post(&rmutex);
//read operatiom
printf("\n\nI'm reader second Reader thread :...the global variable n equals to %d\n",n);
for(int j = 0;j < nowLen-1;j++)
{
for(int k = 0;k < 26;k++)
printf("%c",contentArticle[j][k]);
printf("\n");
}
printf("now the count 0f reader is %d\n",readcount);
printf("now the length 0f content is %d\n",nowLen-1);
sem_wait(&rmutex);
readcount = readcount-1;
if(readcount == 0)sem_post(&wmutex);
sem_post(&rmutex);
sleep(4);
}
}
static void *writerThread(void *arg){
for(int i = 0;i < 10;i++)
{
sem_wait(&wmutex);
//writer operation
n = n+1;
for(int k = 0;k < 26;k++)
contentArticle[nowLen-1][k] = 'z'-k;
nowLen++;
printf("\n\nWriter thread :writing opration the global variable n equals to %d \n",n);
sleep(2);
sem_post(&wmutex);
sleep(3);
}
}