Обработка сбоя потока

Я искал в Интернете следующий вопрос: может ли процесс продолжить выполнение, если один из его порожденных потоков выйдет из строя в cpp?

Кажется, что все ответы предполагают, что это невозможно/может привести к неопределенному поведению (даже после написания обработчика sigsegv), поскольку потоки совместно используют память; или есть какие-то конкретные платформы, на которых можно обрабатывать сбои потоков, что делает вашу платформу кода специфичной.

Редактировать: Я хочу знать -

  • смогу ли я обработать необработанные исключения, создаваемые потоком
  • смогу ли я справиться с общим сбоем (наиболее вероятный ответ на этот вопрос — нет)

Итак, мои вопросы:

Скажем, у меня есть основной процесс, который порождает n потоков. Каждый из этих потоков не хочет взаимодействовать друг с другом; однако они хотят общаться с основным процессом.

  1. Если я сделаю структуры данных, совместно используемые потоками и моим основным процессом, доступными только для чтения; могу ли я в этом случае безопасно обработать сбой потока без какого-либо потенциального UB?

  2. Что меня беспокоит, так это то, что даже если эти потоки не хотят взаимодействовать друг с другом, все равно существует вероятность того, что поток может попытаться получить доступ к памяти какого-либо другого потока (скажем, ошибка в коде), поскольку потоки совместно используют одно и то же адресное пространство. Как мне тогда поступить в этом случае?

  3. Я могу сделать свою кодовую платформу специфичной (хотя я ограничиваюсь cpp). Какие платформы поддерживают обработку сбоя потока?

  4. Является ли повреждение памяти из-за сбоя потока единственным, о чем мне следует беспокоиться при обработке сбоя потока? Скажем, я гарантирую, что поток всегда будет обращаться к своей памяти и никогда не будет обращаться к памяти другого потока. Могу ли я безопасно справиться со сбоем в этой теме? Предоставляется ли cpp какая-либо документация или гарантии относительно того, когда я могу безопасно обработать сбой потока?

Примечание. Я знаю, что мне не нужно было бы беспокоиться о недопустимом доступе к памяти, если бы я использовал процессы; но я не хочу использовать процессы.

Заранее спасибо!

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

paddy 01.03.2024 08:17

Если вам действительно нужно, чтобы что-то запускалось изолированно и не влияло на основной процесс, рассмотрите решение вне процесса. То есть вы, по сути, создаете дочерний процесс и используете IPC для синхронизации с ним данных. Если этот процесс выйдет из строя, это по большей части не повлияет на родительский процесс, в зависимости от того, как реализовано взаимодействие/совместное использование данных.

paddy 01.03.2024 08:21

«Может ли процесс продолжить выполнение, если один из порожденных им потоков выйдет из строя в cpp?» Нет.

n. m. could be an AI 01.03.2024 08:21

Просто думаю вслух: не будет ли это зависеть от ОС? Потому что каждое ядро ​​ОС может по-разному обрабатывать доступ к ограниченным областям памяти. Возможно, популярные ОС, такие как Linux или Windows, делают это, убивая процесс создания, но это не означает, что каждая ОС должна делать то же самое. Или они должны?

kiner_shah 01.03.2024 08:26

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

Pepijn Kramer 01.03.2024 08:48

О какой катастрофе вы говорите? Можете ли вы на самом деле ограничить это конкретными типами сбоев?

Ulrich Eckhardt 01.03.2024 08:49

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

Pepijn Kramer 01.03.2024 08:50

@UlrichEckhardt Хороший вопрос. Возможно, OP смешивает необработанные исключения с реальными сбоями (например, неверный доступ к памяти, использование после проблем с освобождением и т. д.).

Pepijn Kramer 01.03.2024 08:51

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

Ulrich Eckhardt 01.03.2024 08:54

@UlrichEckhardt Извините... Я новичок в использовании потоков. Я хотел бы знать об обоих - необработанных исключениях и фактическом сбое.

TheCodeDemon 01.03.2024 09:04

@kiner_shah Если мы воспользуемся определениями здесь: stackoverflow.com/questions/200469/… (которые совпадают с другими определениями, которые я видел), то ответ в общем случае будет твердым НЕТ. ЕСЛИ процесс находится в общем пространстве памяти, то по определению невозможно быть уверенным в состоянии общего пространства после сбоя одного потока в этом пространстве - потому что этот поток мог выйти из строя, потому что он записывал в общее пространство случайную информацию. и, наконец, наткнулся на что-то, что вызвало неисправность. Процессы изолированы, потоки — нет.

Frodyne 01.03.2024 09:11

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

kiner_shah 01.03.2024 09:23

Ни C++, ни операционная система не будут развертывать изменения в памяти. Это было бы дорого в создании, потребовало бы дополнительной памяти и ресурсов времени выполнения. Так что нет, никакой защиты. В конце концов, вы, как разработчик, несете ответственность: либо предотвратить аннулирование памяти путем проектирования, либо создать механизмы восстановления вручную. И даже несмотря на это, существует множество неисправимых сценариев, когда в вашем коде есть UB (например, сбой потоков).

Pepijn Kramer 01.03.2024 09:53

Ваш вопрос в конце концов даже не о тредах. Основной вопрос по-прежнему заключается в следующем: будет ли моя программа в корректном состоянии после необработанных ошибок или недопустимого доступа к памяти. Кроме того, всякий раз, когда у вас есть код, который может перехватывать исключения ОС (например, недопустимый доступ к памяти), и вы ловите это с помощью (...) и продолжаете... вы стреляете себе в ногу.

Pepijn Kramer 01.03.2024 09:55

Напишите свой код так, чтобы поток не вылетал, это единственное, что нужно сделать. Если поток должен выдать некоторые исключения, вам придется их обработать (т. е. либо из самого потока, либо «распространить» их в основной поток для последующей обработки, используя указатель на исключение).

Fareanor 01.03.2024 10:08

@Fareanor Если вы хотите обработать исключение из «основного» потока, я бы рассмотрел возможность использования std::async и использования std::future get для повторного создания исключения в основном потоке.

Pepijn Kramer 01.03.2024 11:48

@PepijnKramer Точно! Я помню, что раньше делал это, например, с std::packaged_task (но он делает за нас махинации с std::exception_ptr под капотом)

Fareanor 01.03.2024 14:08
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
17
109
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Нет, существует множество общих вещей системного уровня, которые могут вызвать сбои, если не обрабатывать их должным образом. Обработчики файлов, распределители памяти и другие вещи.

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

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

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