读者优先描述
如果读者来:
1) 无读者、写着,新读者可以读;
2) 无写者等待,但有其他读者正在读,新读者可以读;
3) 有写者等待,但有其他读者正在读,新读者可以读;
4) 有写者写,新读者等
如果写者来:
1) 无读者,新写者可以写;
2) 有读者,新写者等待;
3) 有其他写者写或等待,新写者等待
写者优先描述
如果读者来:
1) 无读者、写者,新读者可以读;
2) 无写者等待,但有其他读者正在读,新读者可以读;
3) 有写者等待,但有其他读者正在读,新读者等;
4) 有写者写,新读者等
如果写者来:
1) 无读者,新写者可以写;
2) 有读者,新写者等待;
3) 有其他写者或等待,新写者等待
信号量和互斥锁的区别
l 互斥量用于线程的互斥,信号量用于线程的同步。
这是互斥量和信号量的根本区别,也就是互斥和同步之间的区别。
互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。
同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源
l 互斥量值只能为0/1,信号量值可以为非负整数。
也就是说,一个互斥量只能用于一个资源的互斥访问,它不能实现多个资源的多线程互斥问题。信号量可以实现多个同类资源的多线程互斥和同步。当信号量为单值信号量是,也可以完成一个资源的互斥访问。
l 互斥量的加锁和解锁必须由同一线程分别对应使用,信号量可以由一个线程释放,另一个线程得到。
读者优先
使用互斥锁来确保同一时间只能一个进程写文件,实现互斥。使用信号量来实现访问资源的同步。
首先,写者的代码应该是这样一种形式,才能保证同一时刻只有一个写者修改数据。
考虑到写者对读者的影响是:当任何读者想读时,写者都必须被阻塞;并且,读者阻塞了写者并停止阻塞之前,后续的任何写者都会读者优先于执行。这就如同有一个读者队列,当第一个读者入队时,写者完全被阻塞,直到最后一个读者离开队列。
据此,可以用 readerCnt来统计读者的数量,而用信号量 sem_read来互斥各线程对 readerCnt的访问。
1 /* 2 * 多线程,读者优先 3 */ 4 5 #include "stdio.h" 6 #include <stdlib.h> 7 #include <pthread.h> 8 #include<semaphore.h> 9 10 11 #define N_WRITER 30 //写者数目 12 #define N_READER 5 //读者数目 13 #define W_SLEEP 1 //控制写频率 14 #define R_SLEEP 1 //控制读频率 15 16 17 pthread_t wid[N_WRITER],rid[N_READER]; 18 pthread_mutex_t mutex_write;//同一时间只能一个人写文件,互斥 19 sem_t sem_read;//同一时间只能有一个人访问 readerCnt 20 int data = 0; 21 int readerCnt = 0; 22 void write() 23 { 24 int rd = rand(); 25 printf("write %d ",rd); 26 data = rd; 27 } 28 void read() 29 { 30 printf("read %d ",data); 31 } 32 void * writer(void * in) 33 { 34 // while(1) 35 // { 36 pthread_mutex_lock(&mutex_write); 37 printf("写线程id%d进入数据集 ",pthread_self()); 38 write(); 39 printf("写线程id%d退出数据集 ",pthread_self()); 40 pthread_mutex_unlock(&mutex_write); 41 sleep(W_SLEEP); 42 // } 43 pthread_exit((void *) 0); 44 } 45 46 void * reader (void * in) 47 { 48 // while(1) 49 // { 50 sem_wait(&sem_read); 51 readerCnt++; 52 if(readerCnt == 1){ 53 pthread_mutex_lock(&mutex_write); 54 } 55 sem_post(&sem_read); 56 printf("读线程id%d进入数据集 ",pthread_self()); 57 read(); 58 printf("读线程id%d退出数据集 ",pthread_self()); 59 sem_wait(&sem_read); 60 readerCnt--; 61 if(readerCnt == 0){ 62 pthread_mutex_unlock(&mutex_write); 63 } 64 sem_post(&sem_read); 65 sleep(R_SLEEP); 66 // } 67 pthread_exit((void *) 0); 68 } 69 70 int main() 71 { 72 printf("多线程,读者优先 "); 73 pthread_mutex_init(&mutex_write,NULL); 74 sem_init(&sem_read,0,1); 75 int i = 0; 76 for(i = 0; i < N_WRITER; i++) 77 { 78 pthread_create(&wid[i],NULL,writer,NULL); 79 } 80 for(i = 0; i < N_READER; i++) 81 { 82 pthread_create(&rid[i],NULL,reader,NULL); 83 } 84 sleep(1); 85 return 0; 86 }
为了更明显的看到效果,在main函数中创建了20个写者和5个读者。注意编译时要加上-lpthread指定库。
写者优先
写者优先与读者优先的不同是:如果读者来,有写者等待,但有其他读者正在读,新读者等。
使用两个互斥锁mutex_write,mutex_read和两个信号量sem_read,sem_write来确保访问资源的互斥和同步。
1 #include "stdio.h" 2 #include <stdlib.h> 3 #include <pthread.h> 4 #include<semaphore.h> 5 6 #define N_WRITER 5 //写者数目 7 #define N_READER 20 //读者数目 8 #define W_SLEEP 1 //控制写频率 9 #define R_SLEEP 0.5 //控制读频率 10 11 12 pthread_t wid[N_WRITER],rid[N_READER]; 13 int data = 0; 14 int readerCnt = 0, writerCnt = 0; 15 pthread_mutex_t sem_read; 16 pthread_mutex_t sem_write; 17 pthread_mutex_t mutex_write; 18 pthread_mutex_t mutex_read; 19 20 void write() 21 { 22 int rd = rand(); 23 printf("write %d ",rd); 24 data = rd; 25 } 26 void read() 27 { 28 printf("read %d ",data); 29 } 30 void * writer(void * in) 31 { 32 // while(1) 33 // { 34 sem_wait(&sem_write); 35 {//临界区,希望修改 writerCnt,独占 writerCnt 36 writerCnt++; 37 if(writerCnt == 1){ 38 //阻止后续的读者加入待读队列 39 pthread_mutex_lock(&mutex_read); 40 } 41 } 42 sem_post(&sem_write); 43 44 45 pthread_mutex_lock(&mutex_write); 46 {//临界区,限制只有一个写者修改数据 47 printf("写线程id%d进入数据集 ",pthread_self()); 48 write(); 49 printf("写线程id%d退出数据集 ",pthread_self()); 50 } 51 pthread_mutex_unlock(&mutex_write); 52 53 sem_wait(&sem_write); 54 {//临界区,希望修改 writerCnt,独占 writerCnt 55 writerCnt--; 56 if(writerCnt == 0){ 57 //阻止后续的读者加入待读队列 58 pthread_mutex_unlock(&mutex_read); 59 } 60 } 61 sem_post(&sem_write); 62 sleep(W_SLEEP); 63 // } 64 pthread_exit((void *) 0); 65 } 66 67 void * reader (void * in) 68 { 69 // while(1) 70 // { 71 //假如写者锁定了mutex_read,那么成千上万的读者被锁在这里 72 pthread_mutex_lock(&mutex_read);//只被一个读者占有 73 {//临界区 74 sem_wait(&sem_read);//代码段 1 75 {//临界区 76 readerCnt++; 77 if(readerCnt == 1){ 78 pthread_mutex_lock(&mutex_write); 79 } 80 } 81 sem_post(&sem_read); 82 } 83 pthread_mutex_unlock(&mutex_read);//释放时,写者将优先获得mutex_read 84 printf("读线程id%d进入数据集 ",pthread_self()); 85 read(); 86 printf("读线程id%d退出数据集 ",pthread_self()); 87 sem_wait(&sem_read);//代码段2 88 {//临界区 89 readerCnt--; 90 if(readerCnt == 0){ 91 pthread_mutex_unlock(&mutex_write);//在最后一个并发读者读完这里开始禁止写者执行写操作 92 } 93 } 94 sem_post(&sem_read); 95 96 sleep(R_SLEEP); 97 // } 98 pthread_exit((void *) 0); 99 } 100 101 int main() 102 { 103 printf("多线程,写者优先 "); 104 pthread_mutex_init(&mutex_write,NULL); 105 pthread_mutex_init(&mutex_read,NULL); 106 sem_init(&sem_write,0,1); 107 sem_init(&sem_read,0,1); 108 int i = 0; 109 for(i = 0; i < N_READER; i++) 110 { 111 pthread_create(&rid[i],NULL,reader,NULL); 112 } 113 for(i = 0; i < N_WRITER; i++) 114 { 115 pthread_create(&wid[i],NULL,writer,NULL); 116 } 117 sleep(1); 118 return 0; 119 }