为什么当写锁挂起时可以获得读锁

  • 本文关键字:读锁 挂起 写锁 pthreads
  • 更新时间 :
  • 英文 :


根据pthread_rwlock_rdlock的POSIX文档"如果写线程没有持有该锁并且没有写线程阻塞该锁,则调用线程将获得读锁。"我似乎已经发现,一个读锁可以获得,即使当一个作家被阻塞。我编写的一个小示例的输出如下所示:

first reader acquiring lock...
first reader lock acquired
first writer acquiring lock...
second reader acquiring lock...
second reader lock acquired
first reader releasing lock
second reader releasing lock
first writer lock acquired
first writer releasing lock

关于我的代码有什么问题,或者我没有正确理解的地方,有什么建议吗?顺便说一下:

$ make
gcc -g -I. -I../../isilib -c -Wpointer-arith -Wall -pedantic-errors
-D_POSIX_C_SOURCE=200809L -std=c99 -g rwlock_test1.c -o rwlock_test1.o
gcc rwlock_test1.o -L../../isilib -lisi -lrt -lm -pthread -o rwlock_test1
$ uname -a
Linux BLACKHEART 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:31:23 UTC 
2012 x86_64 x86_64 x86_64 GNU/Linux
$ gcc --version
gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#define PTH_create( a, b, c, d ) 
    (pthread_create( (a), (b), (c), (d) ) != 0 ? abort() : (void)0 )
#define PTH_join( a, b ) 
    (pthread_join( (a), (b) ) != 0 ? abort() : (void)0 )
#define PTH_rwlock_rdlock( a ) 
    (pthread_rwlock_rdlock( (a) ) != 0 ? abort() : (void)0 )
#define PTH_rwlock_wrlock( a ) 
    (pthread_rwlock_wrlock( (a) ) != 0 ? abort() : (void)0 )
#define PTH_rwlock_unlock( a ) 
    (pthread_rwlock_unlock( (a) ) != 0 ? abort() : (void)0 )
static void *firstReader(
    void *arg
);
static void *firstWriter(
    void *arg
);
static void *secondReader(
    void *arg
);
static pthread_rwlock_t rwlock  = PTHREAD_RWLOCK_INITIALIZER;
int main( int argc, char **argv )
{
    pthread_t   thr1;
    pthread_t   thr2;
    pthread_t   thr3;
    PTH_create( &thr1, NULL, firstReader, NULL );
    PTH_create( &thr2, NULL, firstWriter, NULL );
    PTH_create( &thr3, NULL, secondReader, NULL );
    PTH_join( thr1, NULL );
    PTH_join( thr2, NULL );
    PTH_join( thr3, NULL );
    return 0;
}
static void *firstReader( void *arg )
{
    printf( "first reader acquiring lock... n" );
    PTH_rwlock_rdlock( &rwlock );
    printf( "first reader lock acquired n" );
    sleep( 10 );
    printf( "first reader releasing lock n" );
    PTH_rwlock_unlock( &rwlock );
    return NULL;
}
static void *firstWriter( void *arg )
{
    sleep( 2 );
    printf( "first writer acquiring lock... n" );
    PTH_rwlock_wrlock( &rwlock );
    printf( "first writer lock acquired n" );
    sleep( 10 );
    printf( "first writer releasing lock n" );
    PTH_rwlock_unlock( &rwlock );
    return NULL;
}
static void *secondReader( void *arg )
{
    sleep( 5 );
    printf( "second reader acquiring lock... n" );
    PTH_rwlock_rdlock( &rwlock );
    printf( "second reader lock acquired n" );
    sleep( 5 );
    printf( "second reader releasing lock n" );
    PTH_rwlock_unlock( &rwlock );
    return NULL;
}

额外的信息:

来自posix标准:宏_POSIX_THREAD_PRIORITY_SCHEDULING表示是否支持线程执行调度选项。从unistd.h:"如果这些符号被定义,相应的特征总是可用的…"然后列出_POSIX_THREAD_PRIORITY_SCHEDULING。又从posix:"如果线程执行调度选项支持,参与锁的线程执行的调度策略SCHED_FIFOSCHED_RR,调用线程不得获得锁如果一个作家持有锁……。"所以我有一个程序(下图),显示在我的Linux系统_POSIX_THREAD_PRIORITY_SCHEDULING定义,但我不能强迫线程政策SCHED_RR(我也试过SCHED_FIFO, bt的程序中未显示)。

额外的想法吗?谢谢大家……

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#define PTH_create( a, b, c, d ) 
    (pthread_create( (a), (b), (c), (d) ) != 0 ? abort() : (void)0 )
#define PTH_join( a, b ) 
    (pthread_join( (a), (b) ) != 0 ? abort() : (void)0 )
static void *driver(
    void *arg
);
int main( int argc, char **argv )
{
    pthread_attr_t  attr;
    pthread_attr_init( &attr );
    pthread_attr_setschedpolicy( &attr, SCHED_RR );
    pthread_t   thrID;
    PTH_create( &thrID, &attr, driver, NULL );
    printf( "%ldn", _POSIX_THREAD_PRIORITY_SCHEDULING );
    struct sched_param  param;
    int                 policy;
    pthread_getschedparam( thrID, &policy, &param );
    if ( policy == SCHED_FIFO )
        puts( "SCHED_FIFO" );
    else if ( policy == SCHED_RR )
        puts( "SCHED_RR" );
    else if ( policy == SCHED_FIFO )
        puts( "SCHED_FIFO" );
    else if ( policy == SCHED_OTHER )
        puts( "SCHED_OTHER" );
    else
        puts( "eh?" );
    PTH_join( thrID, NULL );
    return 0;
}
static void *driver( void *arg )
{
    sleep( 2 );
    return NULL;
}
$ ./sched_test
200809
SCHED_OTHER

您在POSIX中错过了这个句子:

如果不支持线程执行调度选项,则为由实现定义调用线程是否获得锁当写入器没有持有锁并且有写入器阻塞时锁。

你不能指望POSIX rwlock更偏爱写器而不是读器。

看起来像是Linux pthreads实现中的一个bug。在FreeBSD上正常工作:

first reader acquiring lock... 
first reader lock acquired 
first writer acquiring lock... 
second reader acquiring lock... 
first reader releasing lock 
first writer lock acquired 
first writer releasing lock 
second reader lock acquired 
second reader releasing lock 

简单地说:

    任何数量的读取器都可以同时持有锁。在同一时间最多有一个读取器可以持有锁。
  • 读和写不能同时持有锁。

以你为例:

  • first reader acquiring lock...→OK,因为没有人持有锁
  • first reader lock acquired
  • first writer acquiring lock...→阻塞,因为读取器持有锁
  • second reader acquiring lock...→OK,因为只有读取器持有锁
  • second reader lock acquired
  • first reader releasing lock→第二个读取器仍然持有锁
  • second reader releasing lock→没有人再持有锁
  • first writer lock acquired
  • first writer releasing lock

也没有通用的解决方案:第二个读取器可能比第一个读取器更早释放锁,在这种情况下,上述行为将是有益的。或者第二个读取器可能会运行很长时间,而第一个读取器和写入器会很快结束,在这种情况下,严格按照请求的顺序授予资源将是有益的。

最新更新