Я искал в Интернете следующий вопрос: может ли процесс продолжить выполнение, если один из его порожденных потоков выйдет из строя в cpp?
Кажется, что все ответы предполагают, что это невозможно/может привести к неопределенному поведению (даже после написания обработчика sigsegv), поскольку потоки совместно используют память; или есть какие-то конкретные платформы, на которых можно обрабатывать сбои потоков, что делает вашу платформу кода специфичной.
Редактировать: Я хочу знать -
Итак, мои вопросы:
Скажем, у меня есть основной процесс, который порождает n потоков. Каждый из этих потоков не хочет взаимодействовать друг с другом; однако они хотят общаться с основным процессом.
Если я сделаю структуры данных, совместно используемые потоками и моим основным процессом, доступными только для чтения; могу ли я в этом случае безопасно обработать сбой потока без какого-либо потенциального UB?
Что меня беспокоит, так это то, что даже если эти потоки не хотят взаимодействовать друг с другом, все равно существует вероятность того, что поток может попытаться получить доступ к памяти какого-либо другого потока (скажем, ошибка в коде), поскольку потоки совместно используют одно и то же адресное пространство. Как мне тогда поступить в этом случае?
Я могу сделать свою кодовую платформу специфичной (хотя я ограничиваюсь cpp). Какие платформы поддерживают обработку сбоя потока?
Является ли повреждение памяти из-за сбоя потока единственным, о чем мне следует беспокоиться при обработке сбоя потока? Скажем, я гарантирую, что поток всегда будет обращаться к своей памяти и никогда не будет обращаться к памяти другого потока. Могу ли я безопасно справиться со сбоем в этой теме? Предоставляется ли cpp какая-либо документация или гарантии относительно того, когда я могу безопасно обработать сбой потока?
Примечание. Я знаю, что мне не нужно было бы беспокоиться о недопустимом доступе к памяти, если бы я использовал процессы; но я не хочу использовать процессы.
Заранее спасибо!
Если вам действительно нужно, чтобы что-то запускалось изолированно и не влияло на основной процесс, рассмотрите решение вне процесса. То есть вы, по сути, создаете дочерний процесс и используете IPC для синхронизации с ним данных. Если этот процесс выйдет из строя, это по большей части не повлияет на родительский процесс, в зависимости от того, как реализовано взаимодействие/совместное использование данных.
«Может ли процесс продолжить выполнение, если один из порожденных им потоков выйдет из строя в cpp?» Нет.
Просто думаю вслух: не будет ли это зависеть от ОС? Потому что каждое ядро ОС может по-разному обрабатывать доступ к ограниченным областям памяти. Возможно, популярные ОС, такие как Linux или Windows, делают это, убивая процесс создания, но это не означает, что каждая ОС должна делать то же самое. Или они должны?
Спросите себя, как бы вы отнеслись к продолжению программы после того, как одна из ее частей потерпела неудачу? Я бы очень нервничал, потому что никогда не знаешь, какой еще ущерб был нанесен. Поэтому, даже если программа будет продолжаться, я сделаю все возможное, чтобы быстро и сильно потерпеть неудачу, чтобы я мог, по крайней мере, получить аварийный дамп и некоторую отладочную информацию из ситуации. Итак, НЕТ, вы не можете безопасно обрабатывать сбои, вы можете безопасно обрабатывать исключения, но вам нужно спроектировать и запрограммировать их.
О какой катастрофе вы говорите? Можете ли вы на самом деле ограничить это конкретными типами сбоев?
Худшее, что вы можете сделать, — это продолжать выполнять код с необработанными ошибками, как будто ничего не происходит, только чтобы через несколько часов столкнуться с проблемами. Такой код совершенно невозможно поддерживать/исправить, потому что, вероятно, ни одна из проблем, которые вы видите, не будет воспроизводима.
@UlrichEckhardt Хороший вопрос. Возможно, OP смешивает необработанные исключения с реальными сбоями (например, неверный доступ к памяти, использование после проблем с освобождением и т. д.).
Точно, мы не знаем. Возможно, ОП тоже не знает различий, поэтому это в основном догадки. +1 за совет использовать отдельный процесс для изолирования кода сбоя и возможности восстановления после его сбоя.
@UlrichEckhardt Извините... Я новичок в использовании потоков. Я хотел бы знать об обоих - необработанных исключениях и фактическом сбое.
@kiner_shah Если мы воспользуемся определениями здесь: stackoverflow.com/questions/200469/… (которые совпадают с другими определениями, которые я видел), то ответ в общем случае будет твердым НЕТ. ЕСЛИ процесс находится в общем пространстве памяти, то по определению невозможно быть уверенным в состоянии общего пространства после сбоя одного потока в этом пространстве - потому что этот поток мог выйти из строя, потому что он записывал в общее пространство случайную информацию. и, наконец, наткнулся на что-то, что вызвало неисправность. Процессы изолированы, потоки — нет.
@Frodyne, это имеет смысл. Я просто думаю, а что, если ОС гарантирует правильное состояние общей памяти в случае каких-либо сбоев? Что-то вроде, произошла ошибка -> откатить изменения? Что-то вроде транзакции? Если мой вопрос не имеет смысла, пожалуйста, не стесняйтесь его игнорировать :-)
Ни C++, ни операционная система не будут развертывать изменения в памяти. Это было бы дорого в создании, потребовало бы дополнительной памяти и ресурсов времени выполнения. Так что нет, никакой защиты. В конце концов, вы, как разработчик, несете ответственность: либо предотвратить аннулирование памяти путем проектирования, либо создать механизмы восстановления вручную. И даже несмотря на это, существует множество неисправимых сценариев, когда в вашем коде есть UB (например, сбой потоков).
Ваш вопрос в конце концов даже не о тредах. Основной вопрос по-прежнему заключается в следующем: будет ли моя программа в корректном состоянии после необработанных ошибок или недопустимого доступа к памяти. Кроме того, всякий раз, когда у вас есть код, который может перехватывать исключения ОС (например, недопустимый доступ к памяти), и вы ловите это с помощью (...) и продолжаете... вы стреляете себе в ногу.
Напишите свой код так, чтобы поток не вылетал, это единственное, что нужно сделать. Если поток должен выдать некоторые исключения, вам придется их обработать (т. е. либо из самого потока, либо «распространить» их в основной поток для последующей обработки, используя указатель на исключение).
@Fareanor Если вы хотите обработать исключение из «основного» потока, я бы рассмотрел возможность использования std::async и использования std::future get для повторного создания исключения в основном потоке.
@PepijnKramer Точно! Я помню, что раньше делал это, например, с std::packaged_task (но он делает за нас махинации с std::exception_ptr под капотом)





Нет, существует множество общих вещей системного уровня, которые могут вызвать сбои, если не обрабатывать их должным образом. Обработчики файлов, распределители памяти и другие вещи.
Если вы хотите продолжать движение, вам нужно устранить причину аварии. Примером могут служить исключения (откат состояния до тех пор, пока вы не доберетесь до заведомо хорошего состояния).
Вы не всегда можете это делать. Если, например, вы используете какую-то библиотеку, которую не контролируете, вы не знаете, что они там делают. Для этого вы можете создать новый процесс. Пересылка данных туда и обратно более затруднительна, но обеспечивает достаточную изоляцию, так что один процесс может выйти из строя, не нарушая другого.
Что касается № 1, вы не можете сделать эти структуры данных «только для чтения», чтобы предотвратить № 2, что вполне возможно. Для № 4 отсутствие коррупции – не единственная проблема. Если что-то «падает» нетерминальным образом, например, из-за выдачи исключения, которое каким-то образом приводит к прерыванию потока без остановки всего процесса, тогда объекты и ресурсы могут остаться в недетерминированном состоянии. Это отличается от коррупции. Обычно, если поток выходит из строя должным образом, это приводит к сбою всего процесса. Вы можете попытаться предотвратить это с помощью сбора всех исключений, но это проблематично.