Pthreads - 增加最大读锁数

时间:2014-11-25 15:52:10

标签: c multithreading

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

  

如果出现以下情况,pthread_rwlock_rdlock()和pthread_rwlock_tryrdlock()函数可能会失败:

     

[EAGAIN]

     

无法获取读锁定,因为已超出rwlock的最大读锁定数。

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

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

    return;
}

在程序执行期间的某个时刻,尝试获取此读锁定的两个并发线程将永久挂起在此函数中。看到程序在整个执行过程中正确解锁了这个读写锁,我该怎么做才能解决这个问题?有没有办法增加并发读锁的最大数量?我应该对此函数进行哪些更改才能使程序正常工作?

3 个答案:

答案 0 :(得分:3)

实现了rwlock后,我可以非常自信地说,可能没有办法增加系统上的最大并发读锁数,绝对没有可行的方法。

在某个基本级别,rwlock包含一些当前读锁定数量的计数器,该计数器是一个简单的变量,如int或short,对于每个读锁定递增,在解锁时递减。如果它是一个简短的,你可以大吼大叫你的操作系统提供商使其更大(即使看起来很奇怪,持有64k读锁)如果它是一个int,你的程序可能会被破坏并且不会释放读锁,因为它应该很难在没有错误的地方获得十亿或四个读锁。

我说十亿,因为一个非常流行的实现rwlocks的方法是使用一个32位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)之后没有出错,所以我没有打扰它进一步运行。你可能不想持有那么多读锁。

答案 1 :(得分:2)

您可能忘记释放读锁定。

因为给定pthread_rwlock_t定义(x86_84):

typedef union
{
  struct
  {
    int __lock;
    unsigned int __nr_readers;
    unsigned int __readers_wakeup;
    unsigned int __writer_wakeup;
    unsigned int __nr_readers_queued;
    unsigned int __nr_writers_queued;
    int __writer;
    int __shared;
    unsigned long int __pad1;
    unsigned long int __pad2;
    /* FLAGS must stay at this position in the structure to maintain
       binary compatibility.  */
    unsigned int __flags;
# define __PTHREAD_RWLOCK_INT_FLAGS_SHARED  1
  } __data;

  char __size[__SIZEOF_PTHREAD_RWLOCK_T];
  long int __align;
} pthread_rwlock_t;

如果您忘记释放锁定,则最有可能发生unsigned int __nr_readers的溢出。

pthread_rwlock_rdlock的x86-64实施仅在EAGAIN__nr_readers溢出时返回__nr_readers_queued

    /* Overflow.  */
8:  decl    NR_READERS(%rdi)
    movl    $EAGAIN, %edx
    jmp 9b

    /* Overflow.  */
4:  decl    READERS_QUEUED(%rdi)
    movl    $EAGAIN, %edx
    jmp 9b

答案 2 :(得分:0)

确实有一部分代码没有正确释放锁定,因此它悬挂的原因。尽管如此,自从我开始使用读写锁以来,我一直都有这个问题,因为文档并不清楚最大值的定义位置和方式。感谢您提供的所有精彩和详细的输入。希望这个问题可以作为警告,也可以作为其他程序员的学习机会!