pthread_rBlock的优先级?

pthread_rBlock的优先级?,c,multithreading,pthreads,read-write,C,Multithreading,Pthreads,Read Write,考虑此示例代码: #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 thr

考虑此示例代码:

#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);
    }
}
添加了另一个示例

#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_rwlockrdlock的manpage,读卡器2不应该获取锁,因为有具有相同优先级的writer处于保留状态,并且所有线程的调度策略都设置为SCHED_RR(2)

如果支持线程执行调度选项,则 锁中涉及的线程正在执行调度 策略SCHED_FIFO或SCHED_RR,调用线程不应获取 如果写入程序持有锁,或者如果写入程序的级别更高或相等,则为锁 锁上的优先级被阻塞;否则,调用线程将 拿到锁

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... 
...
只有当两个读卡器都释放了rw锁时,编写器才能获得锁。

仔细阅读手册页

注意你引用的句子

如果写入程序没有持有锁,并且锁上没有被阻止的写入程序,则调用线程将获取读锁

not是否表示如果有写入程序被阻止,读卡器将不会获得锁(
if
而不是
if且仅当

以下内容将使用文档。 引用的句子后面的段落指定了
pthread\u rwlock\u rdlock()
在锁上有被阻止的写入程序时如何操作:

[TPS][Option Start]如果支持线程执行调度选项,并且 锁中涉及的线程正在执行调度 策略SCHED_FIFO或SCHED_RR,调用线程不应获取 如果写入程序持有锁,或者如果写入程序的级别更高或相等,则为锁 优先级在锁上被阻塞;否则,调用线程将 获取锁。[选项结束]

[TPS TSP][Option Start]如果线程执行调度选项为 支持,并且锁中涉及的线程正在使用 SCHED_零星调度策略,调用线程不应获取 如果写入程序持有锁,或者如果写入程序的级别更高或相等,则为锁 优先级在锁上被阻塞;否则,调用线程将 获取锁。[选项结束]

如果不支持线程执行调度选项,则为 实现定义了调用线程是否获取锁 当写入程序未持有锁且有写入程序被阻止时 锁。如果写入程序持有锁,则调用线程不应 获取读锁。如果未获取读锁,则调用 线程将阻塞,直到它能够获得锁。调用线程 如果在调用时持有写锁,则可能会死锁

因此,要提供完整的答案,您需要说明您的实现是否提供了线程执行调度选项,如果提供了,则说明选择了哪个调度策略

要查看当前调度策略是什么(如果您在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);
}
定义GNU源
#包括
#包括
内部主(空)
{
printf(“循环调度策略:%d\n”,SCHED\u RR);
printf(“fifo调度策略:%d\n”,调度fifo);
printf(“其他调度策略:%d\n”,SCHED_other);
pthread_attr_ta;
pthread_getattr_np(pthread_self(),&ta);
int ts;
pthread_attr_getschedpolicy(&ta,&ts);
printf(“当前计划策略:%d\n”,ts);
}
除非当前的调度策略是循环调度或Fifo,否则引用文档的前两段不适用。在这种情况下,调度行为是由实现定义的。特别是,读写器锁很容易偏好读写器,在这种情况下,编写器几乎肯定永远无法运行我们的程序,因为读卡器正在锁保护上序列化
stdout
(通过
printf()
),根据C11标准草案n1570:

7.21输入/输出

7.21.2溪流

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


因为这个锁在保持readlock的同时也保持着,而
sleep()
也会在持有读锁时执行,读卡器在释放读锁和再次获取读锁之间不会做任何事情,任何时候都没有读卡器持有读锁的可能性非常小。因此,编写器从来没有机会。

功能1打印的顺序不是很有趣吗?@user58697我一定错过了复制1我们再次运行程序检查输出,并在我的操作中更新了一个。我试图进一步阅读手册。您引用的3段都说明,在我的情况下,读者不应获取锁,因为我在块上有一个writer,但实现定义的部分除外,这是唯一一个读卡器可能获得锁的情况。我不确定这里定义的实现是什么意思?我的整个程序都在op中,我使用“gcc main.c-lpthread”构建和运行。/a.out在linux平台上。我已将#include更新到我的op中以完成我的程序。
#include
s很好,但它们没有说明任何关于调度策略的内容。我已更新了答案,以显示如何在linux上找到当前的调度策略。好的,我已经阅读了更多关于调度的内容,并开始接受没有简单的方法可以知道g实现定义的行为(运行您的程序给了我0:其他调度策略).所以我试着做了更简单的例子,我在我的作品中更新了。我不希望你在我这个看似无用的问题上浪费更多的时间,但为了学习,我试图理解为什么手册页与我的程序相矛盾,这意味着要么我疯了,要么我在读手册页
#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);
}