Рекурсивный pthread_rwlock_rdlock в Mac OS X / Darwin - PullRequest
1 голос
/ 10 января 2012

У меня есть следующий пример кода (см. Код ниже), который выполняется по потоку:

A: rd-lock
B: wr-lock (waiting)
A: rd-lock (recursive)
A: rd-unlock (recursive)
A: rd-unlock
B: wr-locked (wake after wait)
B: wr-unlock.

По сути, блокировка чтения рекурсивна.Это требуется стандартами POSIX (требует, чтобы блокировки чтения были рекурсивными, но не указаны для блокировок записи).Это работает в Linux, FreeBSD, Solaris, однако не работает в Darwin / Mac OS X.

Пример ниже дает следующий вывод для Linux:

read locking
read locked
write locking
read locking 2
read locked 2
read unlocked 2
read unlocked
write locked
write unlocked 2

В то время как в Darwin он печатает:

read locking
read locked
write locking
read locking 2

И здесь взаимоблокировки (не продолжаются), в основном это не относится к рекурсивной блокировке чтения.

Есть ли что-нибудь, что можно сделать (пометить, определить, связать со специальнымверсия библиотеки) что бы он работал как положено?


Пример кода

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

pthread_rwlock_t lock;

void *thread_r(void *p)
{
    printf("read locking\n");
    pthread_rwlock_rdlock(&lock);
    printf("read locked\n");
    usleep(500*1000);
    printf("read locking 2\n");
    pthread_rwlock_rdlock(&lock);
    printf("read locked 2\n");
    usleep(500*1000);
    pthread_rwlock_unlock(&lock);
    printf("read unlocked 2\n");
    usleep(500*1000);
    pthread_rwlock_unlock(&lock);
    printf("read unlocked\n");
}

void *thread_w(void *p)
{
    usleep(250*1000);
    printf("write locking\n");
    pthread_rwlock_wrlock(&lock);
    printf("write locked\n");
    pthread_rwlock_unlock(&lock);
    printf("write unlocked 2\n");
}

int main()
{
    pthread_t a,b;
    pthread_rwlock_init(&lock,NULL);
    pthread_create(&a,NULL,thread_r,0);
    pthread_create(&b,NULL,thread_w,0);
    pthread_join(a,NULL);
    pthread_join(b,NULL);
    return 0;
}

Ответы [ 2 ]

1 голос
/ 10 января 2012

Только rdlock () поддерживает рекурсивную блокировку:

http://pubs.opengroup.org/onlinepubs/007908799/xsh/pthread_rwlock_rdlock.html

Согласно спецификации Unix, поведение для вызова wrlock () не определено, если поток уже содержитблокировка чтения или записи:

http://pubs.opengroup.org/onlinepubs/007908799/xsh/pthread_rwlock_trywrlock.html

Когда вы работаете с OS X, взгляните на NSRecursiveLock:

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html

0 голосов
/ 10 января 2012

Да, блокировки считывания. Блокировки на rwlocks действительно рекурсивны, до определенного момента. Но в POSIX документах есть строка для pthread_rwlock_rdlock, SUSv2, поскольку Apple поддерживает это:

Вызывающий поток получает блокировку чтения, если записывающее устройство не удерживает блокировку и нет блокирующих запись блокировщиков. Не определено, получает ли вызывающий поток блокировку, когда записывающее устройство не удерживает блокировку и есть ли пишущие, ожидающие блокировку.

Ничего общего с тем, чтобы позволить потоку с существующей блокировкой чтения снова заблокировать чтение. Просто запрос блокировки чтения будет блокироваться, если блокируется писатель (реализации часто отдают предпочтение блокировке записи, чтобы избежать голодания писателя).

Онлайн-документы Apple также поддерживают это:

Функция pthread_rwlock_rdlock () получает блокировку чтения для rwlock, при условии, что rwlock в настоящее время не удерживается для записи, и никакие потоки записи в настоящее время не блокируются для блокировки.

А позже:

Чтобы предотвратить писательский голод, писатели предпочитают читателей.

Снова. нет упоминаний о разрешении рекурсивных блокировок чтения, когда блокировка записи находится в очереди.

...