我有一个使用pthreads实现的多线程C程序,该程序使用读写锁来保护特定的数据结构。 pthread_rwlock_rdlock(应该是阻塞调用)可能会失败,并在调用时返回EAGAIN值。该文档说:

这意味着可以在任何给定时间点获得最大数量的线程来获取读锁定。考虑到这一点,我创建了一个函数,该函数检查返回值并无限循环,直到它实际获得读锁为止。

void
cache_rdlock(void)
{
    int result= pthread_rwlock_rdlock(&cache_access);
    if(result== EAGAIN)
    {
        while((result= pthread_rwlock_rdlock(&cache_access))== EAGAIN);
    }

    return;
}
在程序执行期间的某个时刻,试图获取此读锁的两个并发线程将永久卡在该函数中。看到程序在执行过程中正确地解锁了此读写锁,我该怎么办才能解决此问题?有没有办法增加并发读锁的最大数量?为了使程序正常运行,我应该对此功能进行哪些更改?

最佳答案

实现了rwlocks后,我可以很自信地说,可能无法增加系统上并发读取锁的最大数量,并且绝对没有可移植的方式来做到这一点。

在基本级别上,rwlock包含一些当前读取锁定数量的计数器,并且该计数器是一个简单的变量,例如int或short,对于每个读取锁定都会递增,并在解锁时递减。如果太短,您可以大声喊叫您的操作系统提供者以使其更大(即使持有64k读锁似乎很奇怪),如果它是int,则您的程序可能已损坏并且不会释放读锁,因为它应该要获得十亿个或四个读取锁而在某个地方没有错误则相当困难。

我说十亿是因为实现rwlocks的一种非常流行的方法是使用单个32位int,该int使用最低的两个位来指定写锁定。

这是您可以使用的简单测试程序:

#include <pthread.h>
#include <stdio.h>
#include <limits.h>

int
main(int argc, char **argv)
{
    unsigned long long i;
    pthread_rwlock_t rw;
    int r;

    pthread_rwlock_init(&rw, NULL);


    for (i = 0; i < INT_MAX; i++) {
        if ((r = pthread_rwlock_rdlock(&rw)) != 0)
            break;
        if (i % 10000000 == 0)
            printf("%llu\n", i);
    }

    printf("%d %llu\n", r, i);

    return 0;
}

MacOS的中断次数为1600万(2 ^ 24),Linux在20亿次中断后(2 ^ 31)不会出错,因此我不再为以后运行而烦恼。您可能不想持有那么多读取锁。

10-07 16:37