Система: Fedora 40
.
Используемая библиотека: pthread.h
Я прошу прощения за то, что не предоставил здесь никакого кода, поскольку вся программа состоит из более чем 4000 строк кода и не размещена на Github. Постараюсь объяснить словами.
Программа представляет собой простую базу данных. Это для магазина моих родителей. На компьютере под управлением Linux эта программа работает постоянно. Я использую файлы для каждого клиента, чтобы хранить всю информацию о них. Также есть продавцы, поэтому программа должна иметь возможность открывать и готовить файлы одновременно для многих продавцов и клиентов.
Общая структура программы проста: Запускается поток менеджера, который запускает новый поток для каждого клиента или продавца. До сих пор максимальное количество потоков было 6, но, учитывая большее количество продавцов, я думаю, что лучше иметь один процесс, полностью предназначенный для продавцов. Переключение контекста снижает скорость работы программы, поэтому, когда нужно было открыть файл для продавца, поток менеджера создавал новый процесс.
Каждый поток отображает 4 КБ памяти как АНОНИМНЫЙ и ЧАСТНЫЙ и имеет для этого диспетчер памяти. Эта отображаемая память служит кэшем для любых предыдущих обширных вычислений. Каждый поток имеет свои собственные МЬЮТЕКСЫ и ПЕРЕМЕННЫЕ УСЛОВИЯ. Также имеется очередь запросов и обработчик запросов, управляемый управляющим потоком. Обработчик также имеет собственную переменную блокировки и условия.
Что я нашел: я исследовал программы мультиобработки. Я обнаружил, что после разветвления лучше все заново инициализировать, поэтому для выполнения разветвления я использовал поток Manager. Таким образом, поток Manager был реплицирован. Но я также обнаружил, что отображаемая память, блокировки и условные переменные, распределенная память, в общем, все также унаследовано. Блокировки и условные переменные неработающих потоков также были унаследованы, но они не выполнялись, поэтому я освободил всю выделенную память, уничтожил блокировки и отобразил память, за исключением случаев, когда дело доходило до условных переменных, каждый раз переменная условия третьего потока не могла быть освобождена. . По какой-то причине функция pthread_cond_destroy вообще не возвращает результат.
Я представил проблему
Добро пожаловать в StackOverflow. Пожалуйста, совершите экскурсию и посмотрите Как спросить . В частности, вместо того, чтобы описывать свой код, опубликуйте его как скопированный текст в виде минимального воспроизводимого примера.
Смешивать потоки и процессы может быть непросто, но в этом случае я не понимаю, зачем вам вообще нужно несколько процессов. «Один рабочий поток сталкивается с очень обширной обработкой и запрашивает новый процесс». - Что это может сделать, кроме как замедлить все это? Если бы вы распределили рабочую нагрузку между разными машинами, я бы это понял, но простое создание нового процесса, вероятно, не продвинется далеко.
«унаследованные потоки» хм, вы сталкивались с вариантом проблемы fork-one? Дублируется только та тема, которая вызвала fork
. Если некоторые блокировки были удержаны другими потоками в момент разветвления, они навсегда останутся в дочернем процессе. Основное использование fork — последующий вызов exec. Объединение потоков и разветвление требует боли.
См. также: stackoverflow.com/questions/42034344/…
@Gerhardh Спасибо за предложение. Сделаю репост с более подробной информацией.
Если вы вызываете fork
в многопоточной программе и оказываетесь в дочернем процессе, безопасно вызывать только функции библиотеки , перечисленные здесь (все остальное может использовать внутренние блокировки, которые могут быть вам недоступны). Нет printf
, нет malloc
/free
, нет pthread_cond_*
.
Весь ваш дизайн фундаментально сломан.
Согласно документации 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()
многопоточного родителя.
Большое спасибо! Я исследовал и нашел несколько интересных решений. Вся идея многопоточности мне пока не подходит (мне потребовалась неделя, чтобы разобраться с многопоточностью)
Добро пожаловать в СО. Ваш текст тяжело читать. Вы можете отредактировать свой вопрос, чтобы превратить эту стену текста в более структурированный вопрос. Кроме того, код вообще не отображается. Описание кода не поможет. Вы должны включить соответствующий код. Сокращено до MCVE . Также ознакомьтесь с Как задать вопрос