• linux多线程编程——读者优先、写者优先问题


    读者优先描述

    如果读者来:

    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_writemutex_read和两个信号量sem_readsem_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 }
    写者优先

  • 相关阅读:
    判断IE浏览器的版本号
    解决下拉框第一行出现空格的问题
    Springboot整合log4j2日志全解
    Java NIO之Selector(选择器)
    ZooKeeper客户端 zkCli.sh 节点的增删改查
    Java API操作ZooKeeper
    ReentrantLock(重入锁)功能详解和应用演示
    MySQL高可用集群方案
    Redis高可用之集群配置(六)
    linux free命令详解
  • 原文地址:https://www.cnblogs.com/erbing/p/5626768.html
Copyright © 2020-2023  润新知