2014-11-25 5 views
0

У меня есть многопоточная программа на C, реализованная с помощью pthreads, которая использует блокировку чтения и записи для защиты определенной структуры данных. pthread_rwlock_rdlock, который должен быть блокирующим вызовом, может выйти из строя и вернуть значение EAGAIN при вызове. В документации сказано:Pthreads - Увеличьте максимальное количество блокировок чтения

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; 
} 

В определенный момент во время выполнения программы, два параллельных потоков пытаются получить этот замок чтения будет висеть постоянно в этой функции. Если программа правильно разблокирует эту блокировку чтения и записи во время ее выполнения, что я могу сделать для решения этой проблемы? Есть ли способ увеличить максимальное количество одновременных блокировок чтения? Какие изменения следует внести в эту функцию, чтобы программа работала правильно?

ответ

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 Переполнение, скорее всего, произойдет, если вы забываете снять блокировку.

x86-64 реализация pthread_rwlock_rdlock только когда-либо возвращает 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 
+0

Спасибо за то, что я пролил свет на этот вопрос, я перепроверю базу кода. –

2

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

На некотором базовом уровне rwlock содержит некоторый счетчик числа текущей блокировки чтения, и этот счетчик является простой переменной, такой как int или короткий, который увеличивается для каждой блокировки чтения и уменьшается при разблокировке. Если это коротко, вы можете вопить у своего операционного провайдера, чтобы сделать его больше (хотя кажется, что нечетно держать блокировку чтения 64k), если это int, ваша программа, вероятно, сломана и не освободит блокировки чтения, поскольку она должна быть довольно трудно получить миллиард или 4 считывания замков без ошибки где-то.

Я говорю миллиард, потому что довольно популярный метод для реализации 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 разрывает на 16 миллионов (2^24), Linux не ошибку после 2 млрд (2^31), так что я Жду» не беспокойтесь. Вероятно, вы не хотите удерживать эти многие блокировки чтения.

+0

Я снова проведу проверку базы кода, чтобы убедиться, что я не забываю выпустить блокировку. –

+1

Попробуйте простую программу, которая подсчитывает, сколько раз вы можете получить блокировку чтения до тех пор, пока она не вернет EAGAIN. – Art

0

На самом деле была часть кода, где замок не выпускался должным образом, следовательно, почему он висел. Тем не менее, у меня всегда был этот вопрос в моем сознании с тех пор, как я начал использовать блокировки чтения и записи, поскольку в документации было неясно, где и как определяется максимальное значение. Спасибо за все подробные и подробные материалы, которые вы указали. Надеюсь, этот вопрос будет служить предупреждением и возможностью обучения других программистов!

+0

Если вы используете современные C++ (scoped locks), у вас никогда не будет таких проблем. –

+0

Не знал этого. Моя программа написана на чистом C, поэтому у меня нет такого улучшения в моем распоряжении. –

Смежные вопросы