优先处理pthread_rwlock?

时间:2019-05-04 20:40:49

标签: c multithreading pthreads read-write

考虑此示例代码:

<?php
                    $kodsorgu = mysqli_query($con,"SELECT kod FROM kodlar ORDER BY RAND() LIMIT 1");
                        while($sam=mysqli_fetch_array($kodsorgu))
                            {
                                echo '<center>'.$sam['kod'].'</center>';
                            }       
                            $deleted_code = $sam['kod'];
                            $sil = mysqli_query($con,"DELETE FROM kodlar WHERE kod = '$deleted_code'");
                ?>

我有一个线程在func1中循环,其中请求写锁定1秒钟,另外3个线程在func 2中循环,其中,请求读锁定1秒钟。

pthread_rwlock_rdlock手册页上说:“如果写者不持有该写锁定并且没有写者被阻塞,则调用线程将获得读锁定。”从第5行的输出粘贴中,您可以在“ func 1:尝试锁定”中看到一个作家显然在那儿,所以为什么我的读者无论如何都会获得锁定?第5行之后,每秒打印3行。减少我的读者线程会增加作家获得锁定的机会。

#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);
    }
}

添加了另一个示例

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;
}

根据pthread_rwlock_rdlock的联机帮助页,读取器2不应获取锁,因为存在具有相同优先级的写入器处于保留状态,并且所有线程的调度策略都设置为SCHED_RR(2)。

  

如果支持“线程执行计划”选项,并且   锁中涉及的线程正在按调度执行   策略SCHED_FIFO或SCHED_RR,则调用线程不得获取   如果作家持有锁,或者如果作家的等级更高或相等,则该锁   优先级被锁定;否则,调用线程应   获取锁。

仅当两个阅读器都释放了rw锁时,写入者才获得该锁。

1 个答案:

答案 0 :(得分:1)

仔细阅读手册页

请注意,您引用的句子

  

如果写入者未持有该写入者并且锁上没有任何写入者,则调用线程将获得读取锁定

说,如果有 个作家被阻止(if而不是{{ 1}}。

以下内容将使用POSIX文档。 引用句子后面的段落指定了if and only if的行为,如果的作者锁死了:

  

[TPS] [Option Start]如果支持“线程执行调度”选项,并且   锁中涉及的线程正在按调度执行   策略SCHED_FIFO或SCHED_RR,则调用线程不得获取   如果作家持有锁,或者如果作家的等级更高或相等,则该锁   优先级被锁定;否则,调用线程应   获取锁。 [选项结束]

     

[TPS TSP] [选项开始]如果“线程执行计划”选项为   支持,并且锁中涉及的线程正在使用   SCHED_SPORADIC调度策略,调用线程不得获取   如果作家持有锁,或者如果作家的等级更高或相等,则该锁   优先级被锁定;否则,调用线程应   获取锁。 [选项结束]

     

如果不支持“线程执行计划”选项,则为   实现定义了调用线程是否获取锁   当作家没有持有锁并且有作家被封锁时   锁。如果写者持有该锁,则调用线程不应   获取读锁。如果未获取读锁,则调用   线程将阻塞直到可以获取锁为止。调用线程   如果在进行调用时它持有写锁,则可能会死锁。

因此,要提供完整的答案,将需要您发布实现是否提供了“线程执行调度”选项,如果提供,则选择了哪种调度策略。

要查看当前的调度策略是什么(如果您使用的是Linux),请运行以下程序:

pthread_rwlock_rdlock()

除非当前的调度策略是Round-Robin或Fifo,否则引用的文档的前两段均不适用。在这种情况下,调度行为是实现定义的。尤其是,读取器/写入器锁定很容易首选读取器,在这种情况下,写入器几乎肯定会永远不会运行您的程序,因为读取器正在按照C11草案标准n1570在保护#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); } 的锁上进行序列化(通过stdout)。

  

7.21输入/输出

     

7.21.2流

     

7每个流都有一个关联的锁,该锁用于防止多个执行线程访问一个流时的数据争用,并限制由多个线程执行的流操作的交织。一次只能有一个线程持有此锁。该锁是可重入的:单个线程可以在给定时间多次持有该锁。

由于此锁定在按住readlock的同时被保持,并且printf()在按住readlock的同时也被执行,因此读者在释放readlock和重新获取readlock之间不会做任何事情,这可能是因为是没有读者拿着锁的很小。因此,作家永远没有机会。