qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請訪問 http://qaseven.github.io/

          Linux線程同步之讀寫鎖(rwlock)

           讀寫鎖和互斥量(互斥鎖)很類似,是另一種線程同步機制,但不屬于POSIX標(biāo)準(zhǔn),可以用來同步同一進程中的各個線程。當(dāng)然如果一個讀寫鎖存放在多個進程共享的某個內(nèi)存區(qū)中,那么還可以用來進行進程間的同步,

            和互斥量不同的是:互斥量會把試圖進入已保護的臨界區(qū)的線程都阻塞;然而讀寫鎖會視當(dāng)前進入臨界區(qū)的線程和請求進入臨界區(qū)的線程的屬性來判斷是否允許線程進入。

            相對互斥量只有加鎖和不加鎖兩種狀態(tài),讀寫鎖有三種狀態(tài):讀模式下的加鎖,寫模式下的加鎖,不加鎖。

            讀寫鎖的使用規(guī)則:

            ● 只要沒有寫模式下的加鎖,任意線程都可以進行讀模式下的加鎖;

            ● 只有讀寫鎖處于不加鎖狀態(tài)時,才能進行寫模式下的加鎖;

            讀寫鎖也稱為共享-獨占(shared-exclusive)鎖,當(dāng)讀寫鎖以讀模式加鎖時,它是以共享模式鎖住,當(dāng)以寫模式加鎖時,它是以獨占模式鎖住。讀寫鎖非常適合讀數(shù)據(jù)的頻率遠大于寫數(shù)據(jù)的頻率從的應(yīng)用中。這樣可以在任何時刻運行多個讀線程并發(fā)的執(zhí)行,給程序帶來了更高的并發(fā)度。

            需要提到的是:讀寫鎖到目前為止仍然不是屬于POSIX標(biāo)準(zhǔn),本文討論的讀寫鎖函數(shù)都是有Open Group定義的的。例如下面是在我機器上,編譯器是gcc version 4.4.6,關(guān)于讀寫鎖的定義是包含在預(yù)處理命令中的:

          #if defined __USE_UNIX98 || defined __USE_XOPEN2K

          ... 讀寫鎖相關(guān)函數(shù)聲明...

          #endif

            1、讀寫鎖的初始化和銷毀

          /* Initialize read-write lock  */
           int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock,
                                          __const pthread_rwlockattr_t *__restrict __attr);

          /* Destroy read-write lock */
          extern int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock);

                                                         返回值:成功返回0,否則返回錯誤代碼

            上面兩個函數(shù)分別由于讀寫鎖的初始化和銷毀。和互斥量,條件變量一樣,如果讀寫鎖是靜態(tài)分配的,可以通過常量進行初始化,如下:

          pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

            也可以通過pthread_rwlock_init()進行初始化。對于動態(tài)分配的讀寫鎖由于不能直接賦值進行初始化,只能通過這種方式進行初始化。pthread_rwlock_init()第二個參數(shù)是讀寫鎖的屬性,如果采用默認(rèn)屬性,可以傳入空指針NULL。

            那么當(dāng)不在需要使用時及釋放(自動或者手動)讀寫鎖占用的內(nèi)存之前,需要調(diào)用pthread_rwlock_destroy()進行銷毀讀寫鎖占用的資源。

            2、互斥鎖的屬性設(shè)置

          /* 初始化讀寫鎖屬性對象 */
          int pthread_rwlockattr_init (pthread_rwlockattr_t *__attr);

          /* 銷毀讀寫鎖屬性對象 */
          int pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr);

          /* 獲取讀寫鎖屬性對象在進程間共享與否的標(biāo)識*/
          int pthread_rwlockattr_getpshared (__const pthread_rwlockattr_t * __restrict __attr,
                                                    int *__restrict __pshared);

          /* 設(shè)置讀寫鎖屬性對象,標(biāo)識在進程間共享與否  */
          int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *__attr, int __pshared);

                                                              返回值:成功返回0,否則返回錯誤代碼

            這個屬性設(shè)置和互斥量的基本一樣,具體可以參考互斥量的設(shè)置互斥量的屬性設(shè)置

           3、互斥鎖的使用

          /* 讀模式下加鎖  */
          int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock);

          /* 非阻塞的讀模式下加鎖  */
          int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock);

          # ifdef __USE_XOPEN2K
          /*  限時等待的讀模式加鎖 */
          int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
                                                 __const struct timespec *__restrict __abstime);
          # endif

          /* 寫模式下加鎖  */
          int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock);

          /* 非阻塞的寫模式下加鎖 */
          int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock);

          # ifdef __USE_XOPEN2K
          /* 限時等待的寫模式加鎖 */
          int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock,
                                                 __const struct timespec *__restrict __abstime);
          # endif

          /* 解鎖 */
          int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock);

                                                             返回值:成功返回0,否則返回錯誤代碼

            (1)pthread_rwlock_rdlock()系列函數(shù)

            pthread_rwlock_rdlock()用于以讀模式即共享模式獲取讀寫鎖,如果讀寫鎖已經(jīng)被某個線程以讀模式占用,那么調(diào)用線程就被阻塞。在實現(xiàn)讀寫鎖的時候可以對共享模式下鎖的數(shù)量進行限制(目前不知如何限制)。

            pthread_rwlock_tryrdlock()和pthread_rwlock_rdlock()的唯一區(qū)別就是,在無法獲取讀寫鎖的時候,調(diào)用線程不會阻塞,會立即返回,并返回錯誤代碼EBUSY。

            pthread_rwlock_timedrdlock()是限時等待讀模式加鎖,時間參數(shù)struct timespec * __restrict __abstime也是絕對時間,和條件變量的pthread_cond_timedwait()使用基本一致,具體可以參考pthread_cond_timedwait() 3條件變量的使用

           ?。?)pthread_rwlock_wrlock()系列函數(shù)

            pthread_rwlock_wrlock()用于寫模式即獨占模式獲取讀寫鎖,如果讀寫鎖已經(jīng)被其他線程占用,不論是以共享模式還是獨占模式占用,調(diào)用線程都會進入阻塞狀態(tài)。

            pthread_rwlock_trywrlock()在無法獲取讀寫鎖的時候,調(diào)用線程不會進入睡眠,會立即返回,并返回錯誤代碼EBUSY。

            pthread_rwlock_timedwrlock()是限時等待寫模式加鎖,也和條件變量的pthread_cond_timedwait()使用基本一致,具體可以參考pthread_cond_timedwait()3條件變量的使用。

          (3)pthread_rwlock_unlock()

            無論以共享模式還是獨占模式獲得的讀寫鎖,都可以通過調(diào)用pthread_rwlock_unlock()函數(shù)進行釋放該讀寫鎖。

            下面是測試代碼:

          #include <iostream>
          #include <cstdlib>

          #include <unistd.h>
          #include <pthread.h>

          using namespace std;

          struct{
              pthread_rwlock_t rwlock;
              int product;
          }sharedData = {PTHREAD_RWLOCK_INITIALIZER, 0};

          void * produce(void *ptr)
          {
              for (int i = 0; i < 5; ++i)
              {
                  pthread_rwlock_wrlock(&sharedData.rwlock);
                  sharedData.product = i;
                  pthread_rwlock_unlock(&sharedData.rwlock);

                  sleep(1);
              }
          }

          void * consume1(void *ptr)
          {
              for (int i = 0; i < 5;)
              {
                  pthread_rwlock_rdlock(&sharedData.rwlock);
                  cout<<"consume1:"<<sharedData.product<<endl;
                  pthread_rwlock_unlock(&sharedData.rwlock);

                 &nbsp;++i;
                  sleep(1);
              }
          }

          void * consume2(void *ptr)
          {
              for (int i = 0; i < 5;)
              {
                  pthread_rwlock_rdlock(&sharedData.rwlock);
                  cout<<"consume2:"<<sharedData.product<<endl;
                  pthread_rwlock_unlock(&sharedData.rwlock);

                  ++i;
                  sleep(1);
              }
          }

          int main()
          {
              pthread_t tid1, tid2, tid3;

              pthread_create(&tid1, NULL, produce, NULL);
              pthread_create(&tid2, NULL, consume1, NULL);
              pthread_create(&tid3, NULL, consume2, NULL);

              void *retVal;

              pthread_join(tid1, &retVal);
              pthread_join(tid2, &retVal);
              pthread_join(tid3, &retVal);

              return 0;
          }



           測試結(jié)果如下:

          consume1:0
          consume2:0
          consume2:0
          consume1:1
          consume2:1
          consume1:2
          consume2:2
          consume1:3
          consume2:3
          consume1:4

            如果把consume1的解鎖注釋掉,如下:

          void * consume1(void *ptr)
          {
              for (int i = 0; i < 5;)
              {
                  pthread_rwlock_rdlock(&sharedData.rwlock);
                  cout<<"consume1:"<<sharedData.product<<endl;
                  //pthread_rwlock_unlock(&sharedData.rwlock);

                  ++i;
                  sleep(1);
              }
          }

            程序的執(zhí)行結(jié)果如下:

          consume1:0
          consume2:0
          consume2:0
          consume1:0
          consume2:0
          consume1:0
          consume2:0
          consume1:0
          consume2:0
          consume1:0

            從執(zhí)行結(jié)果可以看出Open Group提供的讀寫鎖函數(shù)是優(yōu)先考慮等待讀模式占用鎖的線程,這種實現(xiàn)的一個很大缺陷就是出現(xiàn)寫入線程餓死的情況。

          posted on 2013-06-28 10:29 順其自然EVO 閱讀(3195) 評論(0)  編輯  收藏 所屬分類: linux

          <2013年6月>
          2627282930311
          2345678
          9101112131415
          16171819202122
          23242526272829
          30123456

          導(dǎo)航

          統(tǒng)計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 肇源县| 禹州市| 湖南省| 廊坊市| 延边| 云霄县| 兴安盟| 屏山县| 故城县| 蒙阴县| 明光市| 红原县| 霍城县| 嘉善县| 米脂县| 赣榆县| 垫江县| 赤水市| 瑞丽市| 合水县| 金阳县| 株洲县| 安达市| 北票市| 高雄县| 凯里市| 石狮市| 沿河| 百色市| 辰溪县| 沭阳县| 简阳市| 永济市| 文山县| 宝清县| 博白县| 家居| 乌海市| 盖州市| 福建省| 巩义市|