簡體   English   中英

優先處理pthread_rwlock?

[英]Prioritization of pthread_rwlock?

考慮以下示例代碼:

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

void *func1(void *);
void *func2(void *);

static pthread_rwlock_t rwLock = PTHREAD_RWLOCK_INITIALIZER;

int main() {

    pthread_t thread1;
    pthread_t thread2;

    pthread_create(&thread1, NULL, func1, NULL);
    sleep(1);
    int i;
    for (i = 0; i < 3; i++) {
        pthread_create(&thread2, NULL, func2, (void *)(i + 1));
    }

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    return 0;
}

void *func1(void *arg) {

    int j;
    for(j = 0; j < 10; j++) {

        printf("func 1: trying lock\n");
        pthread_rwlock_wrlock(&rwLock);
        printf("func 1: lock aquired, sleep 1 sec...\n");

        sleep(1);

        pthread_rwlock_unlock(&rwLock);
    }
}

void *func2(void *arg) {

    int true = 1;
    while(true) {

        pthread_rwlock_rdlock(&rwLock);

        printf("func 2: thread %i: lock aquired, sleep 1 sec... \n", (int)arg);
        sleep(1);

        pthread_rwlock_unlock(&rwLock);
    }
}

我有一個線程在func1中循環,其中要求寫鎖定1秒鍾,另外3個線程在func 2中循環,其中要求讀鎖定1秒鍾。

pthread_rwlock_rdlock手冊頁上,它說:“如果寫者不持有該寫鎖定並且沒有寫者被阻塞,則調用線程將獲得讀鎖定。” 從第5行的輸出粘貼中,您可以在“ func 1:嘗試鎖定”中看到一個作家顯然在那兒,所以為什么我的讀者無論如何都會獲得鎖定? 第5行之后,每秒打印3行。 減少我的讀者線程會增加作家獲得鎖的機會。

func 1: trying lock
func 1: lock aquired, sleep 1 sec...
func 1: trying lock
func 1: lock aquired, sleep 1 sec...
func 1: trying lock
func 2: thread 1: lock aquired, sleep 1 sec... 
func 2: thread 3: lock aquired, sleep 1 sec... 
func 2: thread 2: lock aquired, sleep 1 sec... 
func 2: thread 2: lock aquired, sleep 1 sec... 
func 2: thread 3: lock aquired, sleep 1 sec... 
func 2: thread 1: lock aquired, sleep 1 sec... 
func 2: thread 2: lock aquired, sleep 1 sec... 
func 2: thread 3: lock aquired, sleep 1 sec... 
func 2: thread 1: lock aquired, sleep 1 sec... 
func 2: thread 3: lock aquired, sleep 1 sec... 
func 2: thread 1: lock aquired, sleep 1 sec... 
func 2: thread 2: lock aquired, sleep 1 sec... 
func 2: thread 3: lock aquired, sleep 1 sec... 
func 2: thread 2: lock aquired, sleep 1 sec... 
func 2: thread 1: lock aquired, sleep 1 sec... 
func 2: thread 3: lock aquired, sleep 1 sec... 
func 2: thread 1: lock aquired, sleep 1 sec... 
func 2: thread 2: lock aquired, sleep 1 sec... 
...

添加了另一個示例

#define _GNU_SOURCE

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

#define SIZE 10000

void *writerFunc(void *);
void *readerFunc1(void *);
void *readerFunc2(void *);
int setSchedulePolicyTo2(void);

static pthread_rwlock_t rwLock = PTHREAD_RWLOCK_INITIALIZER;

int main() {

    pthread_t readerThread1;
    pthread_t readerThread2;
    pthread_t writerThread;

    pthread_create(&readerThread1, NULL, readerFunc1, NULL);
    sleep(1);
    pthread_create(&readerThread1, NULL, writerFunc, NULL);
    sleep(1);
    pthread_create(&readerThread2, NULL, readerFunc2, NULL);

    pthread_join(readerThread1, NULL);
    pthread_join(readerThread2, NULL);
    pthread_join(writerThread, NULL);

    return 0;
}

void *writerFunc(void *arg) {
    printf("                writer's scheduling policy: %d\n", setSchedulePolicyTo2());

    printf("writer 1: trying to acquire rw lock...(on hold)\n");
    pthread_rwlock_wrlock(&rwLock); // Note ..._wrlock
    printf("writer 1: rw lock acquired \n");
    pthread_rwlock_unlock(&rwLock);
}

void *readerFunc1(void *arg) {
    printf("                reader1's scheduling policy: %d\n", setSchedulePolicyTo2());

    printf("reader 1: trying to acquire rw lock...(on hold)\n");
    pthread_rwlock_rdlock(&rwLock);
    printf("reader 1: rw lock acquired \n");
    sleep(3); // enough time to let reader 2 to acquire rw lock before this reader releases it.
    pthread_rwlock_unlock(&rwLock);
    printf("reader 1: rw lock released \n");
}

void *readerFunc2(void *arg) {
    printf("                reader2's scheduling policy: %d\n", setSchedulePolicyTo2());

    printf("reader 2: trying to acquire rw lock...(on hold)\n");
    pthread_rwlock_rdlock(&rwLock);
    printf("reader 2: rw lock acquired \n");
    sleep(2);
    pthread_rwlock_unlock(&rwLock);
    printf("reader 2: rw lock released \n");
}

int setSchedulePolicyTo2() {
    struct sched_param sp;
        sp.sched_priority = 10;
    int policy;
    int j;
    if((j = pthread_setschedparam(pthread_self(), SCHED_RR, &sp)) != 0) {
        printf("error: %s \n", strerror(errno));
    }
    if((j = pthread_getschedparam(pthread_self(), &policy, &sp)) != 0) {
        printf("error: %s \n", strerror(errno));
    }
    return policy;
}

輸出:

$ gcc main.c -pthread
$ sudo ./a.out
                reader1's scheduling policy: 2
reader 1: trying to acquire rw lock...(on hold)
reader 1: rw lock acquired 
                writer's scheduling policy: 2
writer 1: trying to acquire rw lock...(on hold)
                reader2's scheduling policy: 2
reader 2: trying to acquire rw lock...(on hold)
reader 2: rw lock acquired 
reader 1: rw lock released 
reader 2: rw lock released 
writer 1: rw lock acquired 
Segmentation fault (end of program)

按照pthread_rwlock_rdlock的手冊頁,因為保持有相同的優先級和所有線程的調度策略作家被設置為SCHED_RR(2)閱讀器2 不應獲取鎖。

如果支持“線程執行調度”選項,並且鎖中涉及的線程正在使用調度策略SCHED_FIFO或SCHED_RR執行,則如果寫者持有該鎖或阻塞了更高或同等優先級的寫者,則調用線程將不會獲取該鎖。在鎖上 否則,調用線程將獲得鎖。

僅當兩個閱讀器都釋放了rw鎖時,編寫者才獲得該鎖。

仔細閱讀手冊。

請注意,您引用的句子

如果寫入者未持有該寫入者並且鎖上沒有任何寫入者,則調用線程將獲得讀取鎖定。

說,如果 (阻塞作家的讀者不會獲取鎖if不是if and only if

以下將使用POSIX文檔。 帶引號的句子之后的段落指定了如果鎖中寫程序被阻塞的情況, pthread_rwlock_rdlock()行為:

[TPS] [選項開始]如果支持“線程執行調度”選項,並且鎖中涉及的線程正在使用調度策略SCHED_FIFO或SCHED_RR執行,則如果寫者持有該鎖或寫者,則調用線程將不獲取該鎖。具有更高或相等優先級的鎖被鎖定; 否則,調用線程將獲得鎖。 [選項結束]

[TPS TSP] [Option Start]如果支持Threads Execution Scheduling選項,並且鎖中涉及的線程正在使用SCHED_SPORADIC調度策略執行,則如果寫入者持有該鎖或如果寫入者持有該鎖,則調用線程將不會獲得該鎖。較高或相等優先級被鎖定在鎖上; 否則,調用線程將獲得鎖。 [選項結束]

如果不支持“線程執行調度”選項,則由實現方式定義,當寫程序不持有該鎖且有寫程序被阻塞時,調用線程是否獲取該鎖。 如果寫者持有該鎖,則調用線程將不獲取讀鎖。 如果未獲取讀鎖,則調用線程將阻塞,直到它可以獲取鎖為止。 如果在調用時它擁有寫鎖,則調用線程可能會死鎖。

因此,要提供完整的答案,將要求您發布實現是否提供了“線程執行調度”選項,如果提供,則選擇了哪種調度策略。

要查看當前的調度策略是什么(如果您使用的是Linux),請運行以下程序:

#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>

int main(void)
{
  printf("round-robin scheduling policy: %d\n", SCHED_RR);
  printf("fifo scheduling policy: %d\n", SCHED_FIFO);
  printf("other scheduling policy: %d\n", SCHED_OTHER);
  pthread_attr_t ta;
  pthread_getattr_np(pthread_self(), &ta);
  int ts;
  pthread_attr_getschedpolicy(&ta, &ts);
  printf("current scheduling policy: %d\n", ts);
}

除非當前的調度策略是Round-Robin或Fifo,否則引用的文檔的前兩段均不適用。 在這種情況下,調度行為是實現定義的。 特別是,讀取器/寫入器鎖很容易傾向於使用讀取器 ,在這種情況下,寫入器幾乎肯定不會為您的程序運行,因為讀取器正在對保護stdout的鎖進行序列化(通過printf() ),根據C11草案標准n1570:

7.21輸入/輸出

7.21.2流

7每個流都有一個關聯的鎖,該鎖用於防止多個執行線程訪問一個流時發生數據爭用,並限制由多個線程執行的流操作的交織。 一次只能有一個線程持有此鎖。 該鎖是可重入的:單個線程可以在給定時間多次持有該鎖。

由於此鎖定是在保持readlock的同時保持的,並且sleep()在保持readlock的同時也會執行,並且讀取器在釋放readlock和再次獲取它之間不執行任何操作,因此在任何時候都沒有讀取器持有readlock鎖很小。 因此,作家永遠沒有機會。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM