Когда можно использовать cond var для синхронизации своего уничтожения / удаления? - PullRequest
6 голосов
/ 29 сентября 2011

Согласно POSIX,

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

Далее указываются операции передачи сигналов и широковещания, чтобы разблокировать один / все потоки, заблокированные в переменной условия.

Таким образом, мне кажется, что следующие формы самосинхронизированного уничтожения должны быть действительными, то есть вызывать pthread_cond_destroy:

  1. Сразу после успешного прохождения сигнала в ожидающем или сигнальном потоке, когда ровно один поток заблокирован в переменной var.
  2. Сразу после успешной трансляции, в любой ожидающей ветке или в широковещательной ветке.

Конечно, это предполагает, что больше официантов не прибудет, и никакие дальнейшие сигналы не будут выполняться впоследствии, что приложение должно гарантировать при использовании pthread_cond_destroy.

Правильно ли я понимаю, что уничтожение действительно в этих ситуациях? И есть ли другие сценарии самосинхронного уничтожения, о которых нужно знать с помощью условных переменных?

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

Ответы [ 3 ]

2 голосов
/ 29 сентября 2011

Нет, я не думаю, что большинство ваших предположений верны. Возврат из pthread_cond_signal или pthread_cond_broadcast не означает, что какой-либо из потоков еще не «разблокирован» из условной переменной, то есть тем потокам, которые должны быть разблокированы, больше не требуется доступ к этой переменной. Стандарт говорит только «разблокировать», а не «при успешном возвращении с этого вызова они будут разблокированы». Последнее будет очень ограничительным для реализаций, поэтому, вероятно, есть веская причина, по которой это сформулировано как есть.

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

0 голосов
/ 15 октября 2011

Комментарий (не ответ):

Это то, что вы имеете в виду?

Global:

// protected by m:
pthread_mutex_t m;
pthread_cond_t c;
bool about_to_pthread_cond_wait = false;
bool condition_waited_on = false;

Тема A:

pthread_mutex_lock (&m);
{ // locked region
    about_to_pthread_cond_wait = true;
    while (condition_waited_on) {
        // pthread_cond_wait (&m, &c) is decomposed here:
        __pthread_mutex_cond_wait_then_unlock (&m, &c);
            // unlocked region
        pthread_mutex_lock (&m);
    }
}
pthread_mutex_unlock (&m);

Резьба B:

for (bool break_loop = false; !break_loop;) {
    pthread_mutex_lock (&m);
    { // locked region
        condition_waited_on = true;

        if (about_to_pthread_cond_wait) {
            pthread_cond_signal (&c);
            pthread_cond_destroy (&c);
            break_loop = true;
        }
    }
    pthread_mutex_unlock (&m);

    pthread_yield ();
}

EDIT:

Я полагаю, pthread_cond_wait (&m, &c); делает:

__pthread_mutex_cond_wait_then_unlock (&m, &c);
pthread_mutex_lock (&m);

__pthread_mutex_cond_wait_then_unlock будет отслеживать сигналы для CV, затем разблокировать мьютекс и идти спать.

Если в CV есть внутренний мьютекс, который __pthread_mutex_cond_wait_then_unlock и pthread_cond_signal должен заблокировать внутри, тогда я предполагаю, что __pthread_mutex_cond_wait_then_unlock делает:

pthread_mutex_lock (&c.int_mutex);
{ // locked region for c.int_state
    __register_wakeup_cond (&c.int_state);
    pthread_mutex_unlock (&m);
}
pthread_mutex_unlock (&c.int_mutex);
// will not touch c.int_state any more 

__sleep_until_registered_wakeups ();

и pthread_cond_signal делает:

pthread_mutex_lock (&c.int_mutex);
{ // locked region for CV internal state
    __wakeup_registered (&c.int_state);
}
pthread_mutex_unlock (&c.int_mutex);

Тогда pthread_cond_destroy будет вызываться только после того, как __pthread_mutex_cond_wait_then_unlock завершится с использованием c.int_state.

0 голосов
/ 15 октября 2011

Хотя я согласен с вашей интерпретацией (и интерпретацией Open POSIX тестового набора) этого языка, использование будет зависеть от реализации. Таким образом, вот краткое изложение некоторых основных реализаций:

Сейф

  • nptl - pthread_cond_destroy() вернет EBUSY, если в состоянии все еще заблокированы потоки. Ответственность за уничтожение будет переходить на потоки, которые сигнализируются не разблокированными.
  • pthread-win32 MSVC - pthread_cond_destroy() вернет EBUSY, если в состоянии все еще заблокированы потоки. Потоки, которые сигнализируются, но не разблокированы, будут выполнены до того, как pthread_cond_destroy() вернет управление приложению.

Безопасно, но блокируется

  • Darwin libc-391 - pthread_cond_destroy() вернет EBUSY, если в состоянии все еще заблокированы потоки. Для заблокированных, но сообщенных тем не предусмотрено никаких положений.
  • dietlibc 0.27 - pthread_cond_destroy() вернет EBUSY, если в состоянии все еще заблокированы потоки. Для заблокированных, но сообщенных тем не предусмотрено никаких положений.

Возможно, не безопасно

  • Android - Зависит от того, чтобы системная реализация __futex_wake_ex была синхронной. Таким образом, pthread_cond_broadcast() должен блокироваться, пока все потоки не проснулись (но не освободили свой мьютекс).
  • различные реализации win32 - Многие полагаются на функцию PulseEvent() для реализации pthread_cond_broadcast(). Это имеет известное состояние гонки

Oddballs

  • OSKit 0.9 - Безопасный, но возвращает EINVAL, если pthread_cond_destroy() вызывается для условной переменной, на которую все еще ссылаются

Редактировать

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

Это означает, что после трансляции ваш поток не может предположить, что переменная условия не используется другими потоками.

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


Редактировать 2

[...] разумно ли ожидать, что деактивация будет действительной в тех же контекстах, уничтожение будет действительным?

Я не думаю, что это разумное ожидание, основанное на рассуждениях в Edit 1. Определенно потребуется дополнительная синхронизация, если вы не сможете использовать pthread_cond_destroy()

...