天天看點

Linux多線程4-2_讀寫鎖

一、讀寫鎖的概念

    1、讀寫鎖與互斥量類似,不過讀寫鎖有更高的并行性。互斥量要麼加鎖要麼不加鎖,而且同一時刻隻允許一個線程對其加鎖。對于一個變量的讀取,

    完全可以讓多個線程同時進行操作

    2、pthread_rwlock_t     rwlock

    讀寫鎖有三種狀态,讀模式下加鎖,寫模式下加鎖,不加鎖。一次隻有一個線程可以占有寫模式下的讀寫鎖,但是多個線程可以同時占有讀模式的

    讀寫鎖

    3、讀寫鎖在寫加鎖狀态時,在它被解鎖之前,所有試圖對這個鎖加鎖的線程都會阻塞。讀寫鎖在讀加鎖狀态時,所有試圖以讀模式對其加鎖的線程

    都會獲得通路權,但是如果線程希望以寫模式對其加鎖,它必須阻塞直到所有的線程釋放鎖。當讀寫鎖一讀模式加鎖時,如果有線程試圖以寫模式對

    其加鎖,那麼讀寫鎖會阻塞随後的讀模式鎖請求。這樣可以避免讀鎖長期占用,而寫鎖達不到請求。

    4、讀寫鎖非常适合對資料結構讀次數大于寫次數的程式,當它以讀模式鎖住時,是以共享的方式鎖住的;當它以寫模式鎖住時,是以獨占的模式鎖

    住的。

二、讀寫鎖的初始化

    1、讀寫鎖在使用之前必須初始化

      int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,  const pthread_rwlockattr_t *restrict attr);

    2、 使用完需要銷毀

      int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

      成功傳回0 ,失敗傳回錯誤碼

三、加鎖和解鎖

    1、讀模式加鎖       

      int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

      int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

    2、寫模式加鎖

      int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

      int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

    3、解鎖

      int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

    成功傳回0

四、手冊

PTHREAD_RWLOCK_DESTROY(3P) POSIX Programmer’s ManualPTHREAD_RWLOCK_DESTROY(3P)

PROLOG

       This  manual page is part of the POSIX Programmer’s Manual.  The Linux implementation of this interface may differ (con-

       sult the corresponding Linux manual page for details of Linux behavior), or the interface  may  not  be  implemented  on

       Linux.

        //這隻是POSIX的手冊,Linux對這個接口的實作可能不一樣,或者有的根本沒有實作這個接口

NAME

       pthread_rwlock_destroy, pthread_rwlock_init - destroy and initialize a read-write lock object

        //銷毀或者初始化一個讀寫鎖

SYNOPSIS

       #include

       int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

       int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,

              const pthread_rwlockattr_t *restrict attr);

DESCRIPTION

       The  pthread_rwlock_destroy()  function  shall  destroy  the read-write lock object referenced by rwlock and release any

       resources used by the lock. The effect of subsequent use of the lock is undefined until the  lock  is  reinitialized  by

       another call to pthread_rwlock_init(). An implementation may cause pthread_rwlock_destroy() to set the object referenced

       by rwlock to an invalid value. Results are undefined if pthread_rwlock_destroy() is called when any thread holds rwlock.

       Attempting to destroy an uninitialized read-write lock results in undefined behavior.

        //pthread_rwlock_destroy()将一個讀寫鎖銷毀,多次銷毀導緻未知的結果。銷毀一個讀寫鎖會使讀寫鎖變成一個無效值,銷毀

        //一個被占用的讀寫鎖導緻未知的結果,銷毀一個未初始化的讀寫鎖導緻未知的結果

       The pthread_rwlock_init() function shall allocate any resources required to use the read-write lock referenced by rwlock

       and initializes the lock to an unlocked state with attributes referenced by attr. If attr is  NULL,  the  default  read-

       write  lock  attributes  shall  be  used;  the  effect  is  the same as passing the address of a default read-write lock

       attributes object. Once initialized, the lock can be used any number of times without being reinitialized.  Results  are

       undefined if pthread_rwlock_init() is called specifying an already initialized read-write lock. Results are undefined if

       a read-write lock is used without first being initialized.

        //pthread_rwlock_init()會初始化一個讀寫鎖,如果初始化的屬性為NULL,那麼會用預設的屬性初始化讀寫鎖。一個已經

        //被初始化的讀寫鎖可以多次使用,重複的初始化一個已經被初始化的讀寫鎖導緻未知的結果。未經過初始化的讀寫鎖在

        //使用的時候會導緻未知的結果

       If the pthread_rwlock_init() function fails, rwlock shall not be initialized and the contents of rwlock are undefined.

        //初始化失敗,讀寫鎖的内容是未知的

       Only the object referenced by rwlock may be used for performing synchronization. The result of referring  to  copies  of

       that    object    in   calls   to   pthread_rwlock_destroy(),   pthread_rwlock_rdlock(),   pthread_rwlock_timedrdlock(),

       pthread_rwlock_timedwrlock(),  pthread_rwlock_tryrdlock(),   pthread_rwlock_trywrlock(),   pthread_rwlock_unlock(),   or

       pthread_rwlock_wrlock() is undefined.

        //一個被複制過來的讀寫鎖在使用的時候回導緻未知的結果

RETURN VALUE

       If  successful,  the pthread_rwlock_destroy() and pthread_rwlock_init() functions shall return zero; otherwise, an error

       number shall be returned to indicate the error.

        //成功傳回0,失敗傳回錯誤碼

       The [EBUSY] and [EINVAL] error checks, if implemented, act as if they were performed immediately  at  the  beginning  of

       processing  for the function and caused an error return prior to modifying the state of the read-write lock specified by

       rwlock.

ERRORS

       The pthread_rwlock_destroy() function may fail if:

       EBUSY  The implementation has detected an attempt to destroy the object referenced by rwlock while it is locked.

        //銷毀一個正在被使用的讀寫鎖導緻EBUSY

       EINVAL The value specified by rwlock is invalid.

        //讀寫鎖的值是無效的,導緻EINVAL

       The pthread_rwlock_init() function shall fail if:

       EAGAIN The system lacked the necessary resources (other than memory) to initialize another read-write lock.

        //系統缺乏除記憶體之外的資源去初始化讀寫鎖

       ENOMEM Insufficient memory exists to initialize the read-write lock.

        //系統缺乏記憶體去初始化讀寫鎖

       EPERM  The caller does not have the privilege to perform the operation.

        //調用者沒有權利去操作讀寫鎖

       The pthread_rwlock_init() function may fail if:

       EBUSY  The implementation has detected an attempt to reinitialize the object referenced by rwlock, a previously initial-

              ized but not yet destroyed read-write lock.

        //重複的初始化一個已經被初始化的讀寫鎖

       EINVAL The value specified by attr is invalid.

        //屬性值是無效的

       These functions shall not return an error code of [EINTR].

        //不會傳回EINTR

       The following sections are informative.

PTHREAD_RWLOCK_RDLOCK(3P)  POSIX Programmer’s Manual PTHREAD_RWLOCK_RDLOCK(3P)

        //這隻是POSIX的手冊,Linux對這個接口的實作可能不一樣,或者有的根本沒有實作這個接口

       pthread_rwlock_rdlock, pthread_rwlock_tryrdlock - lock a read-write lock object for reading

        //在讀模式下鎖住一個讀寫鎖

        //包含頭檔案

       int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

       int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

       The  pthread_rwlock_rdlock()  function  shall apply a read lock to the read-write lock referenced by rwlock. The calling

       thread acquires the read lock if a writer does not hold the lock and there are no writers blocked on the lock.

        //pthread_rwlock_rdlock()申請一個讀鎖,當讀寫鎖沒有被寫模式占用,而且沒有寫要求阻塞,那麼就會得到讀鎖

       If the Thread Execution Scheduling option is supported, and the threads involved in the  lock  are  executing  with  the

       scheduling  policies SCHED_FIFO or SCHED_RR, the calling thread shall not acquire the lock if a writer holds the lock or

       if writers of higher or equal priority are blocked on the lock; otherwise, the calling thread shall acquire the lock.

        //如果線程執行的時候支援系統排程,那麼鎖就會卷入系統排程。如果一個寫要求占有鎖或者有一個和寫要求級别一樣的

        //請求正在因為鎖阻塞,那麼讀要求就無法獲得鎖

       If the Threads Execution Scheduling option is supported, and the threads involved in the lock  are  executing  with  the

       SCHED_SPORADIC scheduling policy, the calling thread shall not acquire the lock if a writer holds the lock or if writers

       of higher or equal priority are blocked on the lock; otherwise, the calling thread shall acquire the lock.

       If the Thread Execution Scheduling option is not supported, it is  implementation-defined  whether  the  calling  thread

       acquires  the lock when a writer does not hold the lock and there are writers blocked on the lock. If a writer holds the

       lock, the calling thread shall not acquire the read lock. If the read lock is not acquired,  the  calling  thread  shall

       block  until  it can acquire the lock.  The calling thread may deadlock if at the time the call is made it holds a write

       lock.

        //如果有寫要求占有鎖,那麼讀要求就無法獲得鎖。如果線程本身占有寫鎖,它繼續申請讀鎖的時候就會造成死鎖

       A thread may hold multiple concurrent read locks on rwlock (that is, successfully call the pthread_rwlock_rdlock() func-

       tion  n  times).  If  so,  the application shall ensure that the thread performs matching unlocks (that is, it calls the

       pthread_rwlock_unlock() function n times).

        //一個線程可以擁有多個讀鎖,但必須有配對的解鎖

       The maximum number of simultaneous read locks that an implementation guarantees can be  applied  to  a  read-write  lock

       shall be implementation-defined. The pthread_rwlock_rdlock() function may fail if this maximum would be exceeded.

        //讀鎖的最大占有量可以繼承過來,如果讀鎖的最大占有量超過系統設定,那麼繼續申請讀鎖就會失敗        

       The  pthread_rwlock_tryrdlock()  function  shall  apply a read lock as in the pthread_rwlock_rdlock() function, with the

       exception that the function shall fail if the equivalent pthread_rwlock_rdlock() call would  have  blocked  the  calling

       thread. In no case shall the pthread_rwlock_tryrdlock() function ever block; it always either acquires the lock or fails

       and returns immediately.

        //pthread_rwlock_tryrdlock()會申請一個讀鎖,如果失敗就會阻塞。 pthread_rwlock_tryrdlock()是不會阻塞的

       Results are undefined if any of these functions are called with an uninitialized read-write lock.

        //如果一個讀寫鎖為經過初始,那麼關于讀寫鎖的一些操作就會失敗

       If a signal is delivered to a thread waiting for a read-write lock for reading, upon return from the signal handler  the

       thread resumes waiting for the read-write lock for reading as if it was not interrupted.

        //如果一個信号發送給正在因為讀鎖阻塞的線程,那麼這個線程在從信号處理函數傳回之後,仍然繼續等待讀鎖,仿佛

        //從未被中斷過

       If  successful,  the pthread_rwlock_rdlock() function shall return zero; otherwise, an error number shall be returned to

       indicate the error.

       The pthread_rwlock_tryrdlock

       enced by rwlock is acquired. Otherwise, an error number shall be returned to indicate the error.

       The pthread_rwlock_tryrdlock() function shall fail if:

       EBUSY  The read-write lock could not be acquired for reading because a writer holds the lock or a writer with the appro-

              priate priority was blocked on it.

        //讀鎖無法被申請,因為一個寫鎖占有讀寫鎖,或者有一個寫請求在阻塞

       The pthread_rwlock_rdlock() and pthread_rwlock_tryrdlock() functions may fail if:

       EINVAL The value specified by rwlock does not refer to an initialized read-write lock object.

        //一個沒有經過初始化的讀寫鎖

       EAGAIN The read lock could not be acquired because the maximum number of read locks for rwlock has been exceeded.

        //讀鎖已經到達最大請求

       The pthread_rwlock_rdlock() function may fail if:

       EDEADLK

              The current thread already owns the read-write lock for writing.

                //目前線程已經擁有寫鎖

PTHREAD_RWLOCK_TRYWRLOCK(3PPOSIX Programmer’s ManuPTHREAD_RWLOCK_TRYWRLOCK(3P)

          //這隻是POSIX的手冊,Linux對這個接口的實作可能不一樣,或者有的根本沒有實作這個接口

       pthread_rwlock_trywrlock, pthread_rwlock_wrlock - lock a read-write lock object for writing

        //申請一個寫鎖

       int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

       int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

       The  pthread_rwlock_trywrlock()  function  shall  apply a write lock like the pthread_rwlock_wrlock() function, with the

       exception that the function shall fail if any thread currently holds rwlock (for reading or writing).

        //申請一個寫鎖,如果有線程已經擁有的讀寫鎖,那麼申請就會失敗

       The pthread_rwlock_wrlock() function shall apply a write lock to the read-write lock referenced by rwlock.  The  calling

       thread  acquires  the  write lock if no other thread (reader or writer) holds the read-write lock rwlock. Otherwise, the

       thread shall block until it can acquire the lock. The calling thread may deadlock if at the time the  call  is  made  it

       holds the read-write lock (whether a read or write lock).

        //申請一個寫鎖,如果沒有其他線程占有讀寫鎖就會成功。否則就會阻塞,直到申請成功。如果線程本身已經占有讀寫鎖

        //那麼線程就會死鎖

       Implementations may favor writers over readers to avoid writer starvation.

        //有一些實作會更偏向于讓寫鎖先獲得,避免寫鎖死等

        //一個沒有初始化的讀寫鎖,操作會失敗

       If  a signal is delivered to a thread waiting for a read-write lock for writing, upon return from the signal handler the

       thread resumes waiting for the read-write lock for writing as if it was not interrupted.

        //如果一個信号發送給正在因為寫鎖阻塞的線程,那麼這個線程在從信号處理函數傳回之後,仍然繼續等待寫鎖,仿佛

       The pthread_rwlock_trywrlock() function shall return zero if the lock for writing on the read-write lock  object  refer-

        //申請成功就傳回0

       If  successful,  the pthread_rwlock_wrlock() function shall return zero; otherwise, an error number shall be returned to

       The pthread_rwlock_trywrlock() function shall fail if:

       EBUSY  The read-write lock could not be acquired for writing because it was already locked for reading or writing.

        //如果讀寫鎖已經被占用,那麼申請就會失敗

       The pthread_rwlock_trywrlock() and pthread_rwlock_wrlock() functions may fail if:

        //一個沒有初始化的讀寫鎖會導緻失敗

       The pthread_rwlock_wrlock() function may fail if:

              The current thread already owns the read-write lock for writing or reading.

                //線程已經占有鎖,那麼就會造成斯諾

五、執行個體

    1、程式架構

Linux多線程4-2_讀寫鎖

    2、源代碼

點選(此處)折疊或打開

/*DATE:            2015-4-5

 *AUTHOR:        DDDDD

 *DESCRIPTION: 驗證可以有多個線程同時擁有讀模式下到讀寫鎖

 *    讀寫鎖在使用之前必須初始化

 *    int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,

 *     const pthread_rwlockattr_t *restrict attr);

 *    成功傳回0 ,失敗傳回錯誤碼

 *    

 *    使用完需要銷毀

 *    int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

 *

 *    讀模式加鎖

 *    int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

 *    int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

 *    寫模式加鎖

 *    int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

 *    int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

 *    解鎖

 *    int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

 */

#include "apue.h"

pthread_rwlock_t rwlock;

int num=0;

void *thread_fun1(void *arg)

{

    int err;

    pthread_rwlock_rdlock(&rwlock);

    printf("thread 1 print num %d\n", num);

    sleep(5);

    printf("thread 1 over\n");

    pthread_rwlock_unlock(&rwlock);

    return (void *)1;

}

void *thread_fun2(void *arg)

    pthread_rwlock_wrlock(&rwlock);

    printf("thread 2 print num %d\n", num);

    printf("thread 2 is over\n");

int main()

    pthread_t tid1, tid2;

    err = pthread_rwlock_init(&rwlock, NULL);

    if(err)

    {

        printf("init rwlock failed\n");

        return ;

    }

    err = pthread_create(&tid1, NULL, thread_fun1, NULL);

        printf("create new thread 1 failed\n");

    err = pthread_create(&tid2, NULL, thread_fun2, NULL);

        printf("create new thread 2 failed\n");

    pthread_join(tid1, NULL);

    pthread_join(tid2, NULL);

    pthread_rwlock_destroy(&rwlock);

    return 0;

繼續閱讀