Запуск метода при уничтожении объекта - PullRequest
3 голосов
/ 13 сентября 2011

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

Конечно, это всего лишь пример не очень хорошего решения, но все же вопрос:

Есть ли какой-нибудь способ предотвратить внутреннюю ситуацию в NotVerySafeClass (запретить запуск methods, если уже был вызван destructor, и заставить destructor ждать, пока не закончится любой запуск method ( давайте предположим, что есть только один method))?

Ответы [ 8 ]

7 голосов
/ 13 сентября 2011

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

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

2 голосов
/ 13 сентября 2011

Что вам нужно, так это разумная политика владения.Почему код уничтожает объект , когда он все еще необходим ?

Без дополнительных подробностей о коде std::shared_ptr, вероятно, решит эту проблему.В зависимости от вашей конкретной ситуации вы можете решить ее с помощью более простой политики.

1 голос
/ 13 сентября 2011

(не для продвижения плохого дизайна), но чтобы ответить на ваши два вопроса:

... запретить запуск методов, если деструктор уже был вызван

Вы можете сделать это с помощью решения, предложенного @snemarch и @Simon (блокировка).Чтобы справиться с ситуацией, когда один поток находится внутри деструктора, в то время как другой ожидает блокировки в начале вашего метода, вам необходимо отслеживать состояние объекта потокобезопасным способом в памяти, разделяемой между потоками.Например, статический атомный int, который деструктор устанавливает в 0, прежде чем снимать блокировку.Метод проверяет int, как только он получает блокировку, и выдает под залог, если его 0.

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

Решение, предложенное @snemarch и @Simon (блокировка), справится с этим.

1 голос
/ 13 сентября 2011

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

В многопоточном программировании необходимо убедиться, что объект не будет удален, если к нему все еще обращаются другие потоки.

Если вы имеете дело с таким кодом, необходимо фундаментальное исправление

1 голос
/ 13 сентября 2011

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

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

0 голосов
/ 13 сентября 2011

Простой ответ: нет.

Несколько более длинный ответ: вы можете защитить каждую функцию-член и деструктор в вашем классе с помощью мьютекса ... добро пожаловать в возможности взаимоблокировки и ночные кошмары производительности.

Соберите толпу и привнесите некоторый дизайнерский смысл в "кого-то", который думал, что параллельное уничтожение было хорошей идеей:)

0 голосов
/ 13 сентября 2011

Почему бы не использовать мьютекс / семафор? В начале любого метода мьютекс блокируется, и деструктор ждет, пока мьютекс не будет разблокирован. Это исправление, а не решение. Возможно, вам следует изменить дизайн части вашего приложения.

0 голосов
/ 13 сентября 2011

Нет. Просто нужно правильно спроектировать программу, чтобы она была поточно-ориентированной.

...