LINUX.ORG.RU

Как можно обеспечить гарантию атомарности new?

 


0

1

Допустим во время вызова конструктора нить переключается и объект остается в неопределенном состоянии, а его пытаются уже где-то использовать что наверное и приводит к падению программы, но очень-очень редко.



Последнее исправление: cetjs2 (всего исправлений: 1)

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

com
()

а чем new отличается от любого другого обращения к объекту? правильно, ничем => и обеспечивать «атомарность» как в случае вызова любой другой функции

next_time ★★★★★
()

Ты же специально придумываешь абсурдные вопросы. На девочковость решил теперь не давить?

anonymous
()
Ответ на: комментарий от com

Как не давать, если конструктор может выполняться в другом потоке? Нужен пример как сообщить остальным, что выполнение конструктора ок, или возникло исключение.

Lzzz
() автор топика
Ответ на: комментарий от Lzzz

Может флаг внутри объекта сделать, что если он установлен, то конструтор закончил работу.

Lzzz
() автор топика
Ответ на: комментарий от Lzzz

у программы должна быть правильная архитектура. с такими вот «флагами», видимостью недоконструированного обьекта несколькими активными тредами - у программы явно архитектура хромает, и костыли в виде флагов, мьютексов и проч, только запутают все дело.

alysnix ★★★
()

Использовать std::unique_ptr, а потом уже после всех операций, потенциально могущих кинуть исключения, забрать указатели через функцию release. Этот сценарий?

dave ★★★★★
()
Ответ на: комментарий от dave

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

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

Lzzz
() автор топика
Ответ на: комментарий от Lzzz

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

alysnix ★★★
()
Ответ на: комментарий от Lzzz

Так люди же явно подсказывают:

Очевидно, надо пересмотреть архитектуру и не давать утекать указателю на объект до полной инициализации объекта. Тогда им никто не сможет воспользоваться пока он до конца не проинициализирован.
у программы должна быть правильная архитектура. с такими вот «флагами», видимостью недоконструированного обьекта несколькими активными тредами - у программы явно архитектура хромает, и костыли в виде флагов, мьютексов и проч, только запутают все дело.

А вот и проблема в дизайне:

Есть некоторый глобальный указатель к примеру.

Нужно избавиться от глобальных переменных.

yetanother ★★
()

Интересно было бы узнать, как вы себе это видите:

  • конструктор объекта во время вызова new вдруг начинает выполняться на другом потоке;
  • в то время как поток, на котором вызвали new, вдруг начинает исполняться дальше не дождавшись завершения вызова new

?

Очень бы хотелось увидеть пример кода, который демонстрирует такое поведение.

eao197 ★★★★★
()
Ответ на: комментарий от Lzzz

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

dave ★★★★★
()
Последнее исправление: dave (всего исправлений: 1)
Ответ на: комментарий от Lzzz

Как бы дать нити конструктора максимальный приоритет, чтобы ее не смогли вытеснить до окончания работы?

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

alysnix ★★★
()
Ответ на: комментарий от yetanother

избавиться от глобальных переменных

Например создается объект-справочник, на основе запросов к БД. Нужно на каждый чих заново создавать локальную копию?

Lzzz
() автор топика
Ответ на: комментарий от Lzzz

Например создается объект-справочник, на основе запросов к БД. Нужно на каждый чих заново создавать локальную копию?

стандартная ситуация. для этого и существуют мьютексы

alysnix ★★★
()
Ответ на: комментарий от Lzzz

Например создается объект-справочник, на основе запросов к БД. Нужно на каждый чих заново создавать локальную копию?

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

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

yetanother ★★
()
Ответ на: комментарий от yetanother

Просто он не должен быть глобальным и видимым всем

пример вполне глобального обьекта - база конфигов например. он может меняться при работе программы и вполне себе глобален, защита создания, записи, чтения производится мьютексом.

alysnix ★★★
()
Ответ на: комментарий от alysnix

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

Lzzz
() автор топика
Ответ на: комментарий от Lzzz

Но после создания объект больше не меняется, его только читают.

если создается один раз в начале, а потом только читают - тогда сначала создаете, потом пускаете читателей. создаете в главном треде, потом пускаете вторичные-читателей.

alysnix ★★★
()
Ответ на: комментарий от alysnix

Синглтон все-таки не совсем глобальная переменная. А я понял, что именно о глобальной переменной идет речь, доступной всем и всегда, судя по вопросу автора. Про мьютекс согласен, это классика.

yetanother ★★
()
Ответ на: комментарий от anonymous

Это не Лизка. Лизка грамотная, а у этого персонажа беда с русским языком.

WitcherGeralt ★★
()
Ответ на: комментарий от WitcherGeralt

Я с тобой согласен в целом, но обманываться ООП для этого не обязательно, а ты, вроде как, это подразумеваешь.

Да нет конечно, ООП не обязателен. Вариантов несколько может быть, тем более я не знаю что у топикстартера там на самом деле.

yetanother ★★
()
Ответ на: комментарий от eao197

Кода еще нет. Просто еше думаю. Например есть одна нить - гуи на Qt, нужно сконструировать объект (долгая операция с запросами в базу), понятно что поток гуи это завесит. Поэтому нужно конструировать объект в другом потоке, задача - дать сигнал другим потокам, что конструктор завершился успешно и по указателю правильный справочник.

Lzzz
() автор топика
Ответ на: комментарий от WitcherGeralt

Данные в базе меняются и объект может устареть, поэтому я решила создавать удалять объект каждые 5 минут.

Lzzz
() автор топика
Ответ на: комментарий от Lzzz

Оператор new вернет управление только когда ему вернет управление конструктор. И пока new не вернет управление, у вас не будет указателя на объект.

Нет, вы конечно, можете внутри конструктора взять this и кому-то каким-то способом этот this отдать.

Но это, имхо, несколько иная ситуация, чем та, о которой вы спросили в стартовом сообщении.

eao197 ★★★★★
()
Ответ на: комментарий от Lzzz

Например есть одна нить - гуи на Qt, нужно сконструировать объект (долгая операция с запросами в базу)

инициализация пускается отдельным тредом, как только он завершается, пускаются остальные треды. ну можно остальные и раньше пустить, тогда они должны встать на флаг окончания инициализации. мьютекс тут не нужен.

alysnix ★★★
()
Ответ на: комментарий от Lzzz

Данные в базе меняются и объект может устареть, поэтому я решила создавать удалять объект каждые 5 минут.

вот те раз. только что говорили что только один раз заполняется… тогда мьютекс надо ставить.

alysnix ★★★
()
Ответ на: комментарий от alysnix

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

Lzzz
() автор топика

Допустим во время вызова конструктора нить переключается и объект остается в неопределенном состоянии, а его пытаются уже где-то использовать

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

i-rinat ★★★★★
()
Ответ на: комментарий от seiken

Кода нет. Поняла, что проблема в самом подходе. Всем спасибо.

Lzzz
() автор топика
Ответ на: комментарий от Lzzz

Наверно буду думать в сторону, что справочник некоторый объект, который работает постоянно, который отвечает за свое состояние и сам бегает в базу каждые 5 минут, а данные отдает через интерфейс

обьект не работает, работает какой-то тред, что апдейтит этот обьект. во время апдейта обьект защищается мьютексом, во время чтения тоже.

alysnix ★★★
()
Ответ на: комментарий от i-rinat

Нет, это совсем не так. Сам указатель, конечно, создан, а вот конструктор может ещё не успеть отработать. Ситуация ничем не отличается от

int* x;
some_func(x);
next_time ★★★★★
()

Пока объект полностью не сконструировался, new не вернёт на него указатель, а значит ни один поток его не увидит, и описанная ситуация невозможна. Она возможна только если явно творить х-ню, например в конструкторе объекта добавлять его в какие-то глобальные контейнеры видимые всем. Если делаете так - то и расхлёбывайте. Хотя более вероятно что у вас просто UB из-за отсутствия синхронизации между потоками.

slovazap ★★★★★
()

Откуда другие потоки взяли указатель на объект?

ya-betmen ★★★★★
()

Лол :-) Хахаха :-) Чего только не приходит в голову писателям на цепепе :-) Лол :-)

anonymous
()

Допустим во время вызова конструктора нить переключается и объект остается в неопределенном состоянии, а его пытаются уже где-то использовать что наверное и приводит к падению программы, но очень-очень редко.

ШУЕ какое-то.

anonymous
()

Херня какая то. Не надо заботиться об атомарности new. new возвращает указатель на уже сконструированный объект. Если у тебя есть указатель на объект, полученный из new, то конструктор уже завершился, объектом можно пользоваться. А пока конструктор не завершился и объект в неопределённом состоянии, никто не знает адреса этого объекта, и пользоваться им попросту невозможно.

debugger ★★★★★
()
Ответ на: комментарий от yetanother

Да даже с глобальным переменными. Пока конструктор не отработает, new не вернёт значение. А значит глобальный указатель будет nullptr. Главное изнутри конструктора никуда не сохранять ссылки на объект, разве что последней командой конструктора. Если топикстартер нас обманул и у него объект не new создаётся, а статически, то это случится гарантированно до вызова main, если он в глобальной переменной. Очевидное решение - запускать все потоки только из main и не раньше.

KivApple ★★★★★
()
Ответ на: комментарий от KivApple

Главное изнутри конструктора никуда не сохранять ссылки на объект, разве что последней командой конструктора.

неполно. есть еще проблема регистрации обьекта в каких-то списках в конструкторах классов-предков, то есть если класс предполагает наследование от него, доступным наружу this делать никак нельзя, хоть последней командой.

alysnix ★★★
()
Ответ на: комментарий от Lzzz

Передавай указатель на объект другим потокам только после new.

anonymous
()
Ответ на: комментарий от KivApple

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

yetanother ★★
()

Кпец. Хоть бы книжки почитал чтоль. Это же в серии «для полных чайников» даже пишут

anonymous
()
Ответ на: комментарий от yetanother

Этому глобальному указателю ещё надо присвоить значение. А если конструктор сам не присваиает, либо присваивает только в конце (нужно учитывать наследование, как сказали выше), то проблем не будет. new возвращает значение только после полной отработки конструктора

KivApple ★★★★★
()
Ответ на: комментарий от KivApple

Если следовать стандарту, то нельзя отдавать this даже в конце, и даже без наследования. До выхода из конструктора объект не создан.

anonymous
()
Ответ на: комментарий от KivApple

Этому глобальному указателю ещё надо присвоить значение.

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

yetanother ★★
()
Ответ на: комментарий от yetanother

Но эта проблема никак не связана с new. Это уже вопрос просто атомарного обновления переменной. Проблема может быть даже если это не указатель, а просто число.

KivApple ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.