zoukankan      html  css  js  c++  java
  • c++读写锁--读者写者问题

    又名:共享-互斥锁,多读者-单写者锁。

    允许多个读者进入临界区,因为只读数据是安全的;

    只允许单写者进入临界区。

    所以,读者进入临界区时,第一个读者对临界区资源加一次锁,最后一个读者解锁(所以又名:共享锁,读锁);写者进入临界区时,每次都需要对临界区加锁解锁(又名:排他锁,写锁)。

    注:semaphore信号量的值为1,等同于互斥量使用。

    第一种实现,读优先

     1 semaphore resource=1;
     2 semaphore rmutex=1;
     3 readcount=0;
     4 
     5 /*
     6    resource.P() is equivalent to wait(resource)
     7    resource.V() is equivalent to signal(resource)
     8    rmutex.P() is equivalent to wait(rmutex)
     9    rmutex.V() is equivalent to signal(rmutex)
    10 */
    11 
    12 writer() {
    13     resource.P();          //Lock the shared file for a writer
    14 
    15     <CRITICAL Section>
    16     // Writing is done
    17 
    18     <EXIT Section>
    19     resource.V();          //Release the shared file for use by other readers. Writers are allowed if there are no readers requesting it.
    20 }
    21 
    22 reader() {
    23     rmutex.P();           //Ensure that no other reader can execute the <Entry> section while you are in it
    24     <CRITICAL Section>
    25     readcount++;          //Indicate that you are a reader trying to enter the Critical Section
    26     if (readcount == 1)   //Checks if you are the first reader trying to enter CS
    27         resource.P();     //If you are the first reader, lock the resource from writers. Resource stays reserved for subsequent readers
    28     <EXIT CRITICAL Section>
    29     rmutex.V();           //Release
    30 
    31     // Do the Reading
    32 
    33     rmutex.P();           //Ensure that no other reader can execute the <Exit> section while you are in it
    34     <CRITICAL Section>
    35     readcount--;          //Indicate that you are no longer needing the shared resource. One fewer reader
    36     if (readcount == 0)   //Checks if you are the last (only) reader who is reading the shared file
    37         resource.V();     //If you are last reader, then you can unlock the resource. This makes it available to writers.
    38     <EXIT CRITICAL Section>
    39     rmutex.V();           //Release
    40 }

    第一个读者进入时,将资源加锁,从而安全访问临界区,不会被写者修改;由于需要对读者计数,所以需要一个rmutex互斥量来保护readcount修改的安全。读者数为0时,释放资源锁。

    第二种实现,写优先

     1 int readcount, writecount;                   //(initial value = 0)
     2 semaphore rmutex, wmutex, readTry, resource; //(initial value = 1)
     3 
     4 //READER
     5 reader() {
     6 <ENTRY Section>
     7   readTry.P();                 //Indicate a reader is trying to enter
     8   rmutex.P();                  //lock entry section to avoid race condition with other readers
     9   readcount++;                 //report yourself as a reader
    10   if (readcount == 1)          //checks if you are first reader
    11     resource.P();              //if you are first reader, lock  the resource
    12   rmutex.V();                  //release entry section for other readers
    13   readTry.V();                 //indicate you are done trying to access the resource
    14 
    15 <CRITICAL Section>
    16 //reading is performed
    17 
    18 <EXIT Section>
    19   rmutex.P();                  //reserve exit section - avoids race condition with readers
    20   readcount--;                 //indicate you're leaving
    21   if (readcount == 0)          //checks if you are last reader leaving
    22     resource.V();              //if last, you must release the locked resource
    23   rmutex.V();                  //release exit section for other readers
    24 }
    25 
    26 //WRITER
    27 writer() {
    28 <ENTRY Section>
    29   wmutex.P();                  //reserve entry section for writers - avoids race conditions
    30   writecount++;                //report yourself as a writer entering
    31   if (writecount == 1)         //checks if you're first writer
    32     readTry.P();               //if you're first, then you must lock the readers out. Prevent them from trying to enter CS
    33   wmutex.V();                  //release entry section
    34   resource.P();                //reserve the resource for yourself - prevents other writers from simultaneously editing the shared resource
    35 <CRITICAL Section>
    36   //writing is performed
    37   resource.V();                //release file
    38 
    39 <EXIT Section>
    40   wmutex.P();                  //reserve exit section
    41   writecount--;                //indicate you're leaving
    42   if (writecount == 0)         //checks if you're the last writer
    43     readTry.V();               //if you're last writer, you must unlock the readers. Allows them to try enter CS for reading
    44   wmutex.V();                  //release exit section
    45 }

    写者优先,所以当第一个写者进入时,尝试对读者加锁,让后面的读者阻塞,即readTry.P();增加了writecount写者计数,不为0时,不会让读者进入,即readTry.V();写者对临界区的访问仍然需要互斥进行,即resource.P(),resource.V();wmutex是为了保护计数的。

    第三种实现,读者写者都公平

     1 int readcount;                // init to 0; number of readers currently accessing resource
     2 
     3 // all semaphores initialised to 1
     4 semaphore resource;           // controls access (read/write) to the resource
     5 semaphore rmutex;             // for syncing changes to shared variable readcount
     6 semaphore serviceQueue;       // FAIRNESS: preserves ordering of requests (signaling must be FIFO)
     7 
     8 //READER
     9 reader() {
    10 <ENTRY Section>
    11   serviceQueue.P();           // wait in line to be serviced
    12   rmutex.P();                 // request exclusive access to readcount
    13   readcount++;                // update count of active readers
    14   if (readcount == 1)         // if I am the first reader
    15     resource.P();             // request resource access for readers (writers blocked)
    16   serviceQueue.V();           // let next in line be serviced
    17   rmutex.V();                 // release access to readcount
    18     
    19 <CRITICAL Section>
    20 //reading is performed
    21     
    22 <EXIT Section>
    23   rmutex.P();                 // request exclusive access to readcount
    24   readcount--;                // update count of active readers
    25   if (readcount == 0)         // if there are no readers left
    26     resource.V();             // release resource access for all
    27   rmutex.V();                 // release access to readcount
    28 }
    29 
    30 //WRITER
    31 writer() {
    32 <ENTRY Section>
    33   serviceQueue.P();           // wait in line to be serviced
    34   resource.P();               // request exclusive access to resource
    35   serviceQueue.V();           // let next in line be serviced
    36     
    37 <CRITICAL Section>
    38 // writing is performed
    39     
    40 <EXIT Section>
    41   resource.V();               // release resource access for next reader/writer
    42 }

    与第一种读优先比较,多了一个serviceQueue互斥锁,读者写者同时请求这个互斥锁,以此达到公平竞争的目的。

     读写锁的缺点:

    上面的实现中,最少需要两个互斥变量。临界区很小的话, 读写锁可能没有直接用一个mutex快; 临界区很大又说明代码写得不好,用不用读写锁需要测试后才知道。

    Reference:

    https://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem

    https://dengzuoheng.github.io/cpp-concurency-pattern-7-rwlock

  • 相关阅读:
    MFC线程(二):线程同步临界区CRITICAL SECTION
    自定义消息
    Visual C++线程同步技术剖析:临界区,时间,信号量,互斥量
    //解析数据函数指针,很爽
    CListCtrl使用方法汇总
    进度条的使用 Progress控件
    CListBOX 用法
    文件操作总结
    CString 十六进制转二进制
    Numpy常用数据结构、数据清洗函数、数据结构series和方法、数据结构dataframe和方法
  • 原文地址:https://www.cnblogs.com/mingbujian/p/14098693.html
Copyright © 2011-2022 走看看