Отложенный вызов bcast для условных переменных - это действительно?
Я реализую переменные условия pthread (основанные на фьютексах Linux), и у меня есть идея, чтобы избежать "эффекта давки" на pthread_cond_broadcast
с общими переменными условия процесса. Для cond-переменных, не относящихся к процессу, операции запроса futex традиционно (т. Е. С помощью NPTL) используются для того, чтобы запросить официантов из futex cond var в futex мьютекса, не вызывая их, но это в общем случае невозможно для cond vars, совместно используемых процессом, так как pthread_cond_broadcast
может не иметь действительного указателя на связанный мьютекс. В худшем случае мьютекс может даже не отображаться в своем пространстве памяти.
Моя идея преодолеть эту проблему состоит в том, чтобы pthread_cond_broadcast
только непосредственно разбудить одного официанта, и пусть этот официант выполнит операцию реквиа при его пробуждении, поскольку у него есть необходимый указатель на мьютекс.
Естественно, есть много уродливых условий гонки, чтобы рассмотреть, придерживаюсь ли я этого подхода, но если они могут быть преодолены, есть ли другие причины, по которым такая реализация будет недействительной или нежелательной? Одна потенциальная проблема, о которой я могу подумать, что, возможно, не удастся преодолеть, это гонка, в которой официант (отдельный процесс), ответственный за требование, убивается до того, как он может действовать, но возможно даже преодолеть это, поставив condvar. futex в списке надежных мьютексов, так что ядро выполняет пробуждение по нему, когда процесс умирает.
2 ответа
Официанты могут принадлежать нескольким адресным пространствам, каждое из которых сопоставило мьютекс, связанный с фьютексом, по другому адресу в памяти. Я не уверен, если FUTEX_REQUEUE
безопасно использовать, когда точка запроса не может быть сопоставлена по одному и тому же адресу во всех официантах; если это так, то это не проблема.
Есть другие проблемы, которые не будут обнаружены надежными фьютексами; например, если выбранный вами официант занят обработчиком сигнала, вы можете ждать сколько угодно долго. [Как обсуждено в комментариях, это не проблема]
Обратите внимание, что с надежными фьютексами, вы должны установить значение фьютекса & 0x3FFFFFFF
быть TID нити, которую нужно разбудить; Вы также должны установить бит FUTEX_WAITERS
если хочешь проснуться. Это означает, что вы должны выбрать, какой поток пробудить из потока вещания, иначе вы не сможете иметь дело со смертью потока сразу после FUTEX_WAKE
, Вам также необходимо разобраться с возможностью смерти потока непосредственно перед тем, как поток waker записывает свой TID в переменную состояния - возможно, было бы неплохо иметь поле 'pending master', которое также зарегистрировано в надежной системе мьютексов.
Я не вижу причин, почему это не может сработать, если вы внимательно следите за выходом из потока. Тем не менее, может быть лучше просто определить в ядре расширение для FUTEX_WAIT
в качестве аргумента он использует точку реквизита и значение сравнения и позволяет ядру обрабатывать это простым и беспроблемным образом.
Я просто не понимаю, почему вы предполагаете, что соответствующий мьютекс может быть неизвестен. Это четко указано
Эффект использования более одного мьютекса для одновременных операций pthread_cond_timedwait() или pthread_cond_wait() в одной и той же условной переменной не определен; то есть переменная условия становится связанной с уникальным мьютексом, когда поток ожидает условную переменную, и это (динамическое) связывание заканчивается, когда возвращается ожидание.
Таким образом, даже для общих мьютексов и условий процесса это должно выполняться, и любой процесс пользовательского пространства должен всегда отображать один и тот же уникальный мьютекс, который связан с условием.
Разрешение пользователям одновременно связывать разные мьютексы с условием - это не то, что я бы поддержал.