Форк в Linux: странный бесконечный цикл при освобождении условной переменной

Контекст

Система: Fedora 40
. Используемая библиотека: pthread.h

Подробности: Если не интересно, читайте «К делу».

Я прошу прощения за то, что не предоставил здесь никакого кода, поскольку вся программа состоит из более чем 4000 строк кода и не размещена на Github. Постараюсь объяснить словами.

Программа представляет собой простую базу данных. Это для магазина моих родителей. На компьютере под управлением Linux эта программа работает постоянно. Я использую файлы для каждого клиента, чтобы хранить всю информацию о них. Также есть продавцы, поэтому программа должна иметь возможность открывать и готовить файлы одновременно для многих продавцов и клиентов.

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

К точке

Каждый поток отображает 4 КБ памяти как АНОНИМНЫЙ и ЧАСТНЫЙ и имеет для этого диспетчер памяти. Эта отображаемая память служит кэшем для любых предыдущих обширных вычислений. Каждый поток имеет свои собственные МЬЮТЕКСЫ и ПЕРЕМЕННЫЕ УСЛОВИЯ. Также имеется очередь запросов и обработчик запросов, управляемый управляющим потоком. Обработчик также имеет собственную переменную блокировки и условия.

Что я нашел: я исследовал программы мультиобработки. Я обнаружил, что после разветвления лучше все заново инициализировать, поэтому для выполнения разветвления я использовал поток Manager. Таким образом, поток Manager был реплицирован. Но я также обнаружил, что отображаемая память, блокировки и условные переменные, распределенная память, в общем, все также унаследовано. Блокировки и условные переменные неработающих потоков также были унаследованы, но они не выполнялись, поэтому я освободил всю выделенную память, уничтожил блокировки и отобразил память, за исключением случаев, когда дело доходило до условных переменных, каждый раз переменная условия третьего потока не могла быть освобождена. . По какой-то причине функция pthread_cond_destroy вообще не возвращает результат.

Предложение LLM

Я представил проблему

Добро пожаловать в СО. Ваш текст тяжело читать. Вы можете отредактировать свой вопрос, чтобы превратить эту стену текста в более структурированный вопрос. Кроме того, код вообще не отображается. Описание кода не поможет. Вы должны включить соответствующий код. Сокращено до MCVE . Также ознакомьтесь с Как задать вопрос

Gerhardh 24.07.2024 10:06

Смешивать потоки и процессы может быть непросто, но в этом случае я не понимаю, зачем вам вообще нужно несколько процессов. «Один рабочий поток сталкивается с очень обширной обработкой и запрашивает новый процесс». - Что это может сделать, кроме как замедлить все это? Если бы вы распределили рабочую нагрузку между разными машинами, я бы это понял, но простое создание нового процесса, вероятно, не продвинется далеко.

Ted Lyngmo 24.07.2024 10:31

«унаследованные потоки» хм, вы сталкивались с вариантом проблемы fork-one? Дублируется только та тема, которая вызвала fork. Если некоторые блокировки были удержаны другими потоками в момент разветвления, они навсегда останутся в дочернем процессе. Основное использование fork — последующий вызов exec. Объединение потоков и разветвление требует боли.

teapot418 24.07.2024 10:50

См. также: stackoverflow.com/questions/42034344/…

teapot418 24.07.2024 10:58

@Gerhardh Спасибо за предложение. Сделаю репост с более подробной информацией.

Programmer Newbie 24.07.2024 14:18

Если вы вызываете fork в многопоточной программе и оказываетесь в дочернем процессе, безопасно вызывать только функции библиотеки , перечисленные здесь (все остальное может использовать внутренние блокировки, которые могут быть вам недоступны). Нет printf, нет malloc/free, нет pthread_cond_*.

teapot418 24.07.2024 15:00
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
89
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Весь ваш дизайн фундаментально сломан.

Согласно документации POSIX для fork():

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

Суммируя:

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

Согласно man-странице Linux для fork():

Обратите внимание на следующие дополнительные моменты:

• Дочерний процесс создается с одним потоком — тем, который называется вилкой(). Все виртуальное адресное пространство родителя копируется в потомке, включая состояния мьютексов, переменные состояния и другие объекты pthreads; использование pthread_atfork(3) может быть полезен при решении проблем. что это может вызвать.

• После fork() в многопоточной программе ребенок может безопасно вызывать только функции, безопасные для асинхронных сигналов (см. signal-safety(7)) до тех пор, пока он не вызовет execve(2).

Список функций, безопасных для асинхронного сигнала, в Linux можно найти на справочной странице Linux signal-safety.7.

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

И это?

Предложение LLM

Я представил проблему

Вот что не так с LLM - они ничего не знают - они просто извергают ту чушь, которой их кормили - типа "клей на пицце". Этот неубедительный совет игнорирует фундаментальные ограничения, налагаемые на дочерний элемент fork() многопоточного родителя.

Большое спасибо! Я исследовал и нашел несколько интересных решений. Вся идея многопоточности мне пока не подходит (мне потребовалась неделя, чтобы разобраться с многопоточностью)

Programmer Newbie 24.07.2024 15:56

Другие вопросы по теме

Похожие вопросы

Почему в структурах инициализация 0 не разрешена, но инициализация 1 является допустимым кодом?
Интерпретация спецификатора формата в printf("%.-1f", 34.14)
Почему я получаю сообщение об ошибке шины с неиспользуемым указателем FILE?
Кто-нибудь знает, почему моя переменная (x) изменила свое значение с 3 на 0 (1 после x++) в этой программе? Я пытаюсь создать систему регистрации, но она перезаписывает
Разница в определении и объявлении не обнаружена gcc?
Опция clang-format для установки штрафа за нарушение директив препроцессора
Обоснование объявления FILE * изменчивым для стандартного ввода в C
Имеет ли `static` какой-либо эффект при компиляции в одной единице перевода?
Программа C, вызываемая в цикле bash, постепенно читает из одного файла и никогда не завершает работу
Можно ли создать приложение на C++ и использовать Flutter в качестве среды графического интерфейса?