2010-03-18 1 views
2

Я синхронизирую процессы чтения и записи в Linux.переменные условия pthread в Linux, нечетное поведение

У меня 0 или более процессов (читателей), которым нужно спать до тех пор, пока они не проснутся, не прочитают ресурс, не вернутся спать и так далее. Обратите внимание: я не знаю, сколько процессов чтения в любой момент. У меня есть один процесс (писатель), который пишет на ресурсе, пробуждает читателей и делает свой бизнес до тех пор, пока не будет готов другой ресурс (в деталях, я разработал не голодное решение для читателей-писателей, но это не важно).

Для реализации механизма сна/пробуждения я использую значение условия Posix, pthread_cond_t. Клиенты вызывают pthread_cond_wait() для переменной, чтобы спать, а сервер выполняет pthread_cond_broadcast(), чтобы разбудить их всех. Как говорится в руководстве, я окружаю эти два вызова с помощью блокировки/разблокировки связанного мьютекса pthread.

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

Что происходит, так это то, что первый клиентский процесс спит и просыпается отлично. Когда я запускаю второй процесс, он блокирует его pthread_cond_wait() и , никогда не просыпается, даже если я уверен (по журналам), вызываемый pthread_cond_broadcast().

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

Почему это поведение? Если я отправлю pthread_cond_broadcast(), каждый процесс должен просыпаться, а не один (и, тем не менее, не всегда один и тот же).

ответ

4

У вас есть set the PTHREAD_PROCESS_SHARED attribute как на вашем condvar, так и на мьютексе?

Для Linux обратитесь следующие man страницы:

Методы, типы, константы и т. Д. Обычно определяются в /usr/include/pthread.h, /usr/include/nptl/pthread.h.

+0

Влад, я нахожусь в Linux, нет такого атрибута (согласно manpages). – janesconference

+0

@james, проверьте ваши файлы заголовков ('find/usr/include/-type f | xargs egrep '(PTHREAD_PROCESS_SHARED | pthread_condattr_setpshared | pthread_mutexattr_setpshared)''), все должно быть в '/ usr/include/pthread.h' , даже в Linux (это POSIX в конце концов, и у меня есть это в моем ящике CentOS 4.x.) – vladr

+0

... в котором также возникает вопрос, в то время как мы на нем, на какой Linux вы? :) ('uname -a; cat/etc/issue') – vladr

1

В документации говорится, что он должен работать ... вы уверены, что это то же условное значение, что и остальные потоки?

Это пример кода из opengroup.org:

pthread_cond_wait(mutex, cond): 
    value = cond->value; /* 1 */ 
    pthread_mutex_unlock(mutex); /* 2 */ 
    pthread_mutex_lock(cond->mutex); /* 10 */ 
    if (value == cond->value) { /* 11 */ 
     me->next_cond = cond->waiter; 
     cond->waiter = me; 
     pthread_mutex_unlock(cond->mutex); 
     unable_to_run(me); 
    } else 
     pthread_mutex_unlock(cond->mutex); /* 12 */ 
    pthread_mutex_lock(mutex); /* 13 */ 


pthread_cond_signal(cond): 
    pthread_mutex_lock(cond->mutex); /* 3 */ 
    cond->value++; /* 4 */ 
    if (cond->waiter) { /* 5 */ 
     sleeper = cond->waiter; /* 6 */ 
     cond->waiter = sleeper->next_cond; /* 7 */ 
     able_to_run(sleeper); /* 8 */ 
    } 
    pthread_mutex_unlock(cond->mutex); /* 9 */ 
3

ли проверить вас какое-то условие, прежде чем ваш процесс на самом деле назвать pthread_cond_wait()?Я спрашиваю, потому что это очень распространенная ошибка: ваш процесс должен не позвонить wait(), если вы не уверены, что какой-либо процесс вызовет signal() (или broadcast()) позже.

concidering этот код (от pthread_cond_wait человека страницы):

  pthread_mutex_lock(&mut); 
      while (x <= y) { 
        pthread_cond_wait(&cond, &mut); 
      } 
      /* operate on x and y */ 
      pthread_mutex_unlock(&mut); 

Если опустить тест while, и только сигнал от другого процесса, когда ваш (х < = у) условие истинно, оно не будет работать, поскольку сигнал только пробуждает процесс, который уже ждет. Если signal() вызывается до того, как другой процесс вызовет wait(), сигнал будет потерян, и процесс ожидания будет навсегда.

РЕДАКТОР: О цикле while. Когда вы сигнализируете один процесс из другого процесса, он устанавливается в «готовом списке», но необязательно запланирован, и ваше условие (x < = y) может быть изменено снова, поскольку никто не удерживает блокировку. Вот почему вам нужно проверять свое состояние каждый раз, когда вы собираетесь ждать. Он всегда должен быть wakeup -> check if the condition is still true -> do work.

надеюсь, что это ясно.

+0

Я не совсем понимаю ваш ответ .. как можно добавить цикл while предотвратить ожидание от блокировки? – janesconference

+0

@janesconference: see my edit – Ben

0

то, что сказал последний плакат. КЛЮЧ со всей ситуационной ситуацией, работающей правильно, заключается в том, что cond-var НЕ сигнализируется до того, как его ожидают. его строго сигнал, который должен использоваться, когда другие (одно или несколько) ждут. когда никто не ждет, его эффективно NOP. который, кстати, НЕ, как я считаю, что ДОЛЖЕН работать, но как он работает.

larry

+0

Вы должны разместить это как комментарий, а не как новый ответ. –