Здесь наши пути расходятся, т.к. я придерживаюсь мнения, что всякие networking-и, как и XML- или JSON-парсеры, не должны быть в стандарте вообще. Подобное должно подключаться к проекту посредством штатного менеджера зависимостей. Но комитет пока такого не родил, а если и родит, то это будет такой же ужас, как и всратые модули из C++20, а то и гораздо хуже.
Мне кажется, что если бы я предложил выбросить из стандарта модули, которые каким-то образом впихнули в C++20, а тех людей, благодаря которым модули внедрили в стандарт, приговорить к 10 годам растрела, то можно было бы собрать еще 200 комментариев.
При условии что приложение не работает со связанными в нескольких файла данными, не обеспечивает работу в транзакционном режиме и еще много чего не делает.
Это не имеет отношение к разговору о том, что чистит за приложением ОС в случае завершения приложения.
Все эти ваши усложнения, типа “связанная в нескольких файла информация” и пр. дребень – это увод разговора совсем в другую сторону. Вы не можете надеятся на то, что ваше приложение в 100% случаев гарантировано получит возможность корректно все это закрыть, завершить/откатить транзакции, послать какие-то комманды на удаленный сервер или подключенному к компьютеру контроллеру и т.д., и т.п.
Не может просто потому, что ваш процесс могут кильнуть из TaskManager или top/htop или вообще каким-то другим способом (например, это может сделать ООМ-killer в Linux-е если выберет ваш процесс жертвой).
Поэтому обеспечение надежности при подобных сбоях – это отдельная прикладная задача, не имеющая прямого отношения к исключениям в коде. И к тому, за что отвечает ОС общего назначения.
И при этом странно читать утверждения о том, что программу можно просто уронить , а система сама все подчистит.
Для огромного спектра приложений, работающих на ОС общего назначения это вполне себе обоснованное предположения для целого ряда запрашиваемых у ОС ресурсов (память, открытые файлы, пайпы, сокеты и пр., и пр.)
Спорить с таким предположением не озвучивая условий когда это не так (например, специализированные ОС реального времени, где может не быть изоляции процессов), мягко говоря, не конструктивно.
Особенно если поток не один, а продукт сложнее (а мне приходилось заниматься разработкой достаточно сложных вещей, как правило, работающих в фоне 24/7) чем небольшая утилитка командной строки.
Вы всерьез думаете, что разговариваете здесь с людьми, которые сложнее примитивных утилит командной строки ничего не делали?
И санитайзерами приходилось пользоваться для выявления неосвобожденных объектов, и с потоками извертываться чтобы один при падении не тащил все остальное…
Многопоточное программирование и изоляция процессов в ОС – это сильно разные вещи. Если мы говорим про ОС общего назначения, то внутри процесса его треды разделяют общую память и один процесс не подчистил за собой, то это утечка памяти в процессе.
Но если процесс выделил память (не важно какой из тредов процесса) или взял у ОС какой-то ресурс (открыл файл, пайп или сокет), то ОС общего назначения обязана все это подчистить за процессом после того, как процесс завершился.
Если этого не происходит, то либо в ОС где-то есть глюк, либо ситуация на самом деле не так проста.
Да и “транзакция” может быть сложнее чем обычная транзакция БД.
Я вообще не знаю что именно тов.@aeder подразумевал под “транзацией”. Но вот то, что он сказал про закрытие файлов и освобождение памяти именно таким образом и происходит в ОС общего назначения.
Выглядит как свидетельство очевидца – где-то что-то когда-то как-то, но где что и как точно не помню.
Какая-то изоляция там есть, конечно.
Там как раз достаточная изоляция для контекста разговора, а именно “Освобождение памяти, закрытие файлов и откат транзакций - это всё обеспечивает операционная система.” Освобождение памяти и закрытие файлов после завершения процесса – это как раз непосредственная задача ОС общего назначения. И Windows/Linux/FreeBSD из того, что я видел, с этой задачей прекрасно справляются.
Не зря же в винде/линухе всякие докеры-шмокеры придумывают… Как раз по причине недостаточной изоляции процессов.
Ну вот а я не наблюдал начиная с Windows NT 3.51. И если после снятого процесса в Windows не возвращалась память, то значит ситуация там была гораздо более сложная, чем кажется на первый взгляд. Может эта память разделялась с каким-то другим процессом или же процесс на самом деле оставался “висеть” и не был полностью “убит” операционкой.
Блокировки файлов были свойственны сетевым дискам.
При работе с USB-флешками в Windows подобное наблюдается регулярно. Посмотришь на содержимое флешки в FAR-е, затем закроешь FAR, попытаешься безопасно извлечь накопитель, а Windows говорит, что он еще каким-то приложением используется.
Правда, качество работы Windows c каждым годом все ниже и ниже…
Т.е. если ваш процесс динамически выделил память а потом ее не освободил на выходе, возникает утечка.
Не доводилось наблюдать такого в Windows, Linux и FreeBSD.
Проблемы с тем, что какой-то файл оказался заблокированным в Windows после того, как работавший с ним процесс упал, случаются. Но здесь я не в курсе того, кто виновник – Windows, который не чистит ресурсы, или же сам процесс, который запустил дочерный процесс и на самом деле файл блокируется дочерним процессом.
Давайте сразу оговорим, что это с точки зрения задач
Давайте я еще раз сошлюсь на текст статьи и акцентирую внимание на том, что существующие исключения разделили мир C++ на два лагеря: в одном исключения под строгим запретом (основные причины: ресурсоемкость /недопустимо для низкоуровневого системного программирования/ и непредсказуемость /недопустимо для реального времени и высоких нагрузок/), в другом исключения используются.
Это разделение, имхо, пагубно влияет на экосистему. Например, библиотеки и фреймворки, сделанные в одном лагере, могут оказаться неприменимы во втором. Что есть плохо. Даже совсем плохо.
Соответственно, моя точка зрения состоит в том, чтобы объединить эти два лагеря добавив в язык исключения, которые будут нести предсказуемые накладные расходы. Использование этих исключений будет похоже на то, что обсуждается в данной ветке (начиная, как минимум, с этого комментария). И это вполне себе рабочий способ. Не без недостатков, но уж точно лучше, чем когда исключения совсем под запретом. Или когда исключения разрешены, но кто-то решается сделать throw -1;
А является ли эта непредсказуемость (надо сказать, очень условная) действительно проблемой?
Насколько я знаю, действительно является и действительно проблемой. В проектах, связанных с реальным временем, исключения под запретом. Как и работа с динамической памятью после начальной инициализации.
Ой ли? А утечки памяти откуда берутся? А сообщение “файл невозможно удалить т.к. он занят другим процессом” после падения этого самого процесса откуда берется?
Справедливости ради: а какие ОС общего назначения не подчищают память и не закрывают автоматически открытые процессом файлы?
Что до невозможности удалить файл, который занят другим процессом, то такое запросто возможно, когда приложение использует многопроцессную архитектуру: родитель запускает один или несколько дочерних процессов. Какой-то из них падает (например, родитель), а остальные не могут по каким-то причинам диагностировать исчезновение родителя и продолжают держать открытыми ресурсы.
Еще весело бывает, когда два процесса общаются друг с другом через shared-memory и один из них внезапно падает. Что именно остается при этом в shared-memory – никому не ведомо.
Пытаться это сделать, когда у вас в коде непредусмотренное состояние в которое непонятно как попали и непонятно что делать - верный путь к тому, чтобы сделать значительно хуже.
Непонятно каким образом это относится к исключением и почему на других подходах этого не будет.
Ну вот представьте себе, у вас - редактор для файла сложного формата. Пользователь наредактировал всякого, данные у вас в памяти и тут возникла ошибка.
Хороший пример, кстати говоря. Вот у вас редактор, вы в нем корпели несколько часов, затем параллельно запустили какую-то тяжелую программулину и выбрали всю имеющуюся оперативную память. Захотели в редакторе сделать какое-то действие, поймали bad_alloc. И что, вы ратуете за то, что редактор должен просто упасть?
Если вы просто “упадёте” - файл останется без этого наредактированного, но хоть корректный.
Тут больше вопросов к формату файлов и процедуры записи, которая, кстати говоря, может оборваться по независящим от вас причинам.
Т.е. тут по определению ощутимо меньше накладных расходов.
Принципиальный момент не в “меньше” или “больше”. А в том, что главная претензия к существующим C++ным исключениям в таких областях как реальное время – это непредсказуемость операции выброса исключения. Т.к. все это находится под контролем у компилятора и стандартной библиотеки, то разработчик написав throw не знает к чему именно этот самый throw приведет: где и как будет создан экземпляр исключения, куда будет передано управление, сколько займет поиск подходящего catch и пр.
В случае с явным возвратом объекта вместо выброса исключения накладных расходов, на самом-то деле, может оказаться даже больше. Но зато эти расходы могут контролироваться самим разработчиком. Например, он может сам управлять тем, где и как будет создан экземпляр “исключения” (и не обязательно это может быть динамическая память, которая не предсказуема по определению). Кроме того, стоимость возврата условного std::expected с конкретными типами вполне себе можно оценить и эта стоимость вряд ли будет “плавать” в зависимости от фазы луны компилятора, стандартной библиотеки, текущего состояния динамической памяти и пр. факторов.
Затем, что здесь полностью все в ваших руках и вы можете предсказать сколько времени займет прокидывание ошибки наверх. Тогда как с исключениями об этом можно только гадать.
Здесь наши пути расходятся, т.к. я придерживаюсь мнения, что всякие networking-и, как и XML- или JSON-парсеры, не должны быть в стандарте вообще. Подобное должно подключаться к проекту посредством штатного менеджера зависимостей. Но комитет пока такого не родил, а если и родит, то это будет такой же ужас, как и всратые модули из C++20, а то и гораздо хуже.
cppreference некоторое время был
на последнем издыханиив режиме read-only.Второе дыхание он, к счастью, обретает вот прямо сейчас.
Мне кажется, что если бы я предложил выбросить из стандарта модули, которые каким-то образом впихнули в C++20, а тех людей, благодаря которым модули внедрили в стандарт, приговорить к 10 годам растрела, то можно было бы собрать еще 200 комментариев.
Возможно, std::reference_wrapper или какая-то вариация на эту тему поможет.
Это не имеет отношение к разговору о том, что чистит за приложением ОС в случае завершения приложения.
Все эти ваши усложнения, типа “связанная в нескольких файла информация” и пр. дребень – это увод разговора совсем в другую сторону. Вы не можете надеятся на то, что ваше приложение в 100% случаев гарантировано получит возможность корректно все это закрыть, завершить/откатить транзакции, послать какие-то комманды на удаленный сервер или подключенному к компьютеру контроллеру и т.д., и т.п.
Не может просто потому, что ваш процесс могут кильнуть из TaskManager или top/htop или вообще каким-то другим способом (например, это может сделать ООМ-killer в Linux-е если выберет ваш процесс жертвой).
Поэтому обеспечение надежности при подобных сбоях – это отдельная прикладная задача, не имеющая прямого отношения к исключениям в коде. И к тому, за что отвечает ОС общего назначения.
Поэтому хватит флудить.
Для огромного спектра приложений, работающих на ОС общего назначения это вполне себе обоснованное предположения для целого ряда запрашиваемых у ОС ресурсов (память, открытые файлы, пайпы, сокеты и пр., и пр.)
Спорить с таким предположением не озвучивая условий когда это не так (например, специализированные ОС реального времени, где может не быть изоляции процессов), мягко говоря, не конструктивно.
Вы всерьез думаете, что разговариваете здесь с людьми, которые сложнее примитивных утилит командной строки ничего не делали?
Многопоточное программирование и изоляция процессов в ОС – это сильно разные вещи. Если мы говорим про ОС общего назначения, то внутри процесса его треды разделяют общую память и один процесс не подчистил за собой, то это утечка памяти в процессе.
Но если процесс выделил память (не важно какой из тредов процесса) или взял у ОС какой-то ресурс (открыл файл, пайп или сокет), то ОС общего назначения обязана все это подчистить за процессом после того, как процесс завершился.
Если этого не происходит, то либо в ОС где-то есть глюк, либо ситуация на самом деле не так проста.
Я вообще не знаю что именно тов.@aeder подразумевал под “транзацией”. Но вот то, что он сказал про закрытие файлов и освобождение памяти именно таким образом и происходит в ОС общего назначения.
Выглядит как свидетельство очевидца – где-то что-то когда-то как-то, но где что и как точно не помню.
Там как раз достаточная изоляция для контекста разговора, а именно “Освобождение памяти, закрытие файлов и откат транзакций - это всё обеспечивает операционная система.” Освобождение памяти и закрытие файлов после завершения процесса – это как раз непосредственная задача ОС общего назначения. И Windows/Linux/FreeBSD из того, что я видел, с этой задачей прекрасно справляются.
Ну-ну, ну-ну.
А это как вообще?
Тут остается только воскликнуть “Да что вы говорите?!!!”
Ну вот а я не наблюдал начиная с Windows NT 3.51. И если после снятого процесса в Windows не возвращалась память, то значит ситуация там была гораздо более сложная, чем кажется на первый взгляд. Может эта память разделялась с каким-то другим процессом или же процесс на самом деле оставался “висеть” и не был полностью “убит” операционкой.
При работе с USB-флешками в Windows подобное наблюдается регулярно. Посмотришь на содержимое флешки в FAR-е, затем закроешь FAR, попытаешься безопасно извлечь накопитель, а Windows говорит, что он еще каким-то приложением используется.
Правда, качество работы Windows c каждым годом все ниже и ниже…
Со времен перехода на Windows NT и ее наследников еще ни разу не видел, чтобы при закрытии проблемного приложения память системе не отдавалась.
Тогда разговор вряд ли будет предметным.
Где?
Не доводилось наблюдать такого в Windows, Linux и FreeBSD.
Проблемы с тем, что какой-то файл оказался заблокированным в Windows после того, как работавший с ним процесс упал, случаются. Но здесь я не в курсе того, кто виновник – Windows, который не чистит ресурсы, или же сам процесс, который запустил дочерный процесс и на самом деле файл блокируется дочерним процессом.
Давайте я еще раз сошлюсь на текст статьи и акцентирую внимание на том, что существующие исключения разделили мир C++ на два лагеря: в одном исключения под строгим запретом (основные причины: ресурсоемкость /недопустимо для низкоуровневого системного программирования/ и непредсказуемость /недопустимо для реального времени и высоких нагрузок/), в другом исключения используются.
Это разделение, имхо, пагубно влияет на экосистему. Например, библиотеки и фреймворки, сделанные в одном лагере, могут оказаться неприменимы во втором. Что есть плохо. Даже совсем плохо.
Соответственно, моя точка зрения состоит в том, чтобы объединить эти два лагеря добавив в язык исключения, которые будут нести предсказуемые накладные расходы. Использование этих исключений будет похоже на то, что обсуждается в данной ветке (начиная, как минимум, с этого комментария). И это вполне себе рабочий способ. Не без недостатков, но уж точно лучше, чем когда исключения совсем под запретом. Или когда исключения разрешены, но кто-то решается сделать
throw -1;Насколько я знаю, действительно является и действительно проблемой. В проектах, связанных с реальным временем, исключения под запретом. Как и работа с динамической памятью после начальной инициализации.
Справедливости ради: а какие ОС общего назначения не подчищают память и не закрывают автоматически открытые процессом файлы?
Что до невозможности удалить файл, который занят другим процессом, то такое запросто возможно, когда приложение использует многопроцессную архитектуру: родитель запускает один или несколько дочерних процессов. Какой-то из них падает (например, родитель), а остальные не могут по каким-то причинам диагностировать исчезновение родителя и продолжают держать открытыми ресурсы.
Еще весело бывает, когда два процесса общаются друг с другом через shared-memory и один из них внезапно падает. Что именно остается при этом в shared-memory – никому не ведомо.
Так с точки зрения предсказумости и контроля со стороны разработчика это и является ключевым.
Поэтому я и сказал выше “Но да, удобство всего этого под вопросом.”
Непонятно каким образом это относится к исключением и почему на других подходах этого не будет.
Хороший пример, кстати говоря. Вот у вас редактор, вы в нем корпели несколько часов, затем параллельно запустили какую-то тяжелую программулину и выбрали всю имеющуюся оперативную память. Захотели в редакторе сделать какое-то действие, поймали bad_alloc. И что, вы ратуете за то, что редактор должен просто упасть?
Тут больше вопросов к формату файлов и процедуры записи, которая, кстати говоря, может оборваться по независящим от вас причинам.
Принципиальный момент не в “меньше” или “больше”. А в том, что главная претензия к существующим C++ным исключениям в таких областях как реальное время – это непредсказуемость операции выброса исключения. Т.к. все это находится под контролем у компилятора и стандартной библиотеки, то разработчик написав throw не знает к чему именно этот самый throw приведет: где и как будет создан экземпляр исключения, куда будет передано управление, сколько займет поиск подходящего catch и пр.
В случае с явным возвратом объекта вместо выброса исключения накладных расходов, на самом-то деле, может оказаться даже больше. Но зато эти расходы могут контролироваться самим разработчиком. Например, он может сам управлять тем, где и как будет создан экземпляр “исключения” (и не обязательно это может быть динамическая память, которая не предсказуема по определению). Кроме того, стоимость возврата условного
std::expectedс конкретными типами вполне себе можно оценить и эта стоимость вряд ли будет “плавать” в зависимости отфазы луныкомпилятора, стандартной библиотеки, текущего состояния динамической памяти и пр. факторов.Затем, что здесь полностью все в ваших руках и вы можете предсказать сколько времени займет прокидывание ошибки наверх. Тогда как с исключениями об этом можно только гадать.