Почему нельзя выполнять несколько pthread_join в одном потоке?

Из https://computing.llnl.gov/tutorials/pthreads/:

Присоединяющийся поток может соответствовать одному вызову pthread_join(). Логической ошибкой является попытка нескольких объединений в одном и том же потоке.

Также из "man pthread_join":

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

Однако с точки зрения программиста вполне логично, что несколько потоков могут захотеть дождаться завершения одного потока (аналогично барьерам).

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

Есть ли какая-то техническая причина для этого ограничения?


person SHH    schedule 18.09.2015    source источник
comment
Как только pthread_join() возвращается, освобождаются последние ресурсы, связанные с завершенным потоком. Никакой другой pthread_join() не может коснуться этой нити, потому что от нее ничего не осталось. Так и должно быть, иначе как библиотека pthread узнает, когда освобождать эти ресурсы? Если несколько потоков могут присоединиться к одному pthread, у вас будет постоянная утечка ресурсов для каждого завершенного потока.   -  person EOF    schedule 19.09.2015
comment
Итак, ресурс (возвращаемое значение) завершившегося потока хранится в памяти до тех пор, пока ПЕРВЫЙ поток не присоединится и не потребует его? Так же, как в порядке живой очереди?   -  person SHH    schedule 19.09.2015
comment
Не совсем. Первый пришел, первый обслужен, и если кто-то еще придет позже, придется адски платить.   -  person EOF    schedule 19.09.2015
comment
Я могу сказать, в чем причина, но это могут быть неприятные обходные пути, такие как pthread_detach и, возможно, поиск деструктора или блокировок, которые освобождаются для выбора.   -  person jgmjgm    schedule 19.02.2019


Ответы (2)


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

Действительно, POSIX уже считает эту функцию скорее удобством, чем примитивом, для поддержки очень и очень распространенного варианта использования: один поток ожидает завершения другого.

Первый абзац стандарта POSIX.1-2008 pthread_join ОБОСНОВАНИЕ немного длинновато, но содержит много уместных замечаний:

Функция pthread_join() — это удобная функция, доказавшая свою полезность в многопоточных приложениях. Это правда, что программист мог бы имитировать эту функцию, если бы она не была предоставлена ​​путем передачи дополнительного состояния как части аргумента функции start_routine(). Завершающий поток установит флаг, указывающий на завершение, и передаст условие, являющееся частью этого состояния; присоединяющийся поток будет ожидать этой условной переменной. Хотя такой метод позволил бы потоку ожидать более сложных условий (например, ожидание завершения нескольких потоков), ожидание завершения отдельного потока считается широко полезным. Кроме того, включение функции pthread_join() никоим образом не мешает программисту кодировать такие сложные ожидания. Таким образом, хотя это и не примитив, включение pthread_join() в этот том POSIX.1-2008 было сочтено ценным.

person pilcrow    schedule 18.09.2015
comment
Спасибо за конкретное упоминание из документа. Узнал, что pthread_join существует для удобства (поскольку вы можете реализовать более сложные ожидания, используя другие методы). - person SHH; 20.09.2015

Существует огромная разница между pthreads Posix и объектами ядра Windows (с которыми я явно полагаю, что вы знакомы). Я нахожу его с неприятными ограничениями, и вы упомянули только один. Для этого нет реальной технической причины, кроме текущих деталей реализации (да, состояние потока не сохраняется в памяти после соединения, но почему?). Другим очень неприятным ограничением является отсутствие возможности объединить несколько потоков в одном вызове, что препятствует мультиплексированию потоков.

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

person SergeyA    schedule 18.09.2015
comment
Точно так же, как не все языки имеют автоматическую сборку мусора, не все библиотеки потоков могут отслеживать, кто возможно все еще имеет дескриптор завершенного потока. С тем же успехом вы можете спросить, почему вам не разрешено free() выделять ресурсы дважды. - person EOF; 19.09.2015
comment
@EOF, нет. Вам не нужно спрашивать «у кого еще есть дескриптор». Вы просто не освобождаете дескриптор при присоединении. Вот так просто и ясно. И если вашему приложению не хватает памяти из-за того, что вы использовали всю память с вашими дескрипторами потоков, значит, с вашим приложением что-то не так. - person SergeyA; 19.09.2015
comment
Я не согласен и переворачиваю ситуацию: если ваша библиотека потоков не может постоянно создавать новые потоки, значит, с вашей библиотекой потоков что-то не так. - person EOF; 19.09.2015
comment
Я не поклонник программирования под Windows и большой поклонник Linux и таких вещей, как pthreads, но я должен согласиться с этим утверждением. Это разочаровывающие ограничения в pthreads. Это хуже, потому что я видел, как многие люди оборачивают pthreads для языков высокого уровня, а также экспортируют это ограничение из-за вдохновения или отсутствия такового, которое pthreads дает в этом отношении, а не по необходимости (IE, потоки изящно закрываются, чтобы они могли просто выскочить из своего изменение состояния в очередь с мьютексами в управляющий поток). - person jgmjgm; 19.02.2019