Re[2]: Снова this в конструкторе
От: found Россия ak239.ru
Дата: 01.03.12 20:14
Оценка:
Здравствуйте, Caracrist, Вы писали:

F>>Реальная задача:

F>>Внутри объекта хранится объект — событие и ссылка на внешнее событие. В конструкторе необходимо запустить поток, в котором сигнализировать событием объекта и остановиться в ожидании внешнего события.
F>>В итоге происходит следующая последовательность действий:
F>>1. В конструкторе создается объект событие
F>>2. В конструкторе создается поток, приемом описанным выше
F>>3. Внутри функции потока событие объекта устанавливается в сигнальное состояние
F>>4. Функция потока останавливается в ожидании внешнего события

F>>Как правило, приведенная схема работает. Но когда потоков становится действительно много, иногда возникает ситуация, когда пункт 3 алгоритма приводит к ошибке обращения к памяти, при чем с помощью отладчика, удалось выяснить, что неверен не только объект внутреннего события, но и все остальные поля класса, из чего я делаю вывод, что неверен указатель this, относительно которого вызывается функция член класса.

C>Вот список возможных проблем:
C>* Время жизни объекта короче времени жизни потока. От сюда: кирдык.
C>* Вызываемая функция не потокобезопасна(как в примере: ++ там не защищён)
C>* Вызов виртуальной функции из потока, равно как и вызов виртуальной функции из конструктора = UB
C>* dynamic_cast из потока, равно как и из конструктора = UB
C>* исключение брошенное из дальнейшего кода в конструторе приведёт в конечном счёте к инвалидации объекта
C>* исключение при инициализации следующего из массива объекта Foo oops[3]; приведёт в конечном счёте к инвалидации объекта

F>>В чем может быть реальная проблема в пункте 3?


C>я думаю этот список легко дополнить... у тебя какой вариант?


* В деструкторе объекта поток при необходимости завершается, время жизнь объекта > времени жизни потока
* Сам вызов функции происходит в потоке следующим образом:
вход в критическую секцию, привязанную к конкретному объекту, вызов функции, которая сигнализирует событие, ожидание внешнего события, выход из критической секции.
* Класс ни от чего не наследуется и от него тоже ничего не наслудется
* Есть только static_cast при запуске потока, описанный в примере
* Дальше кода в конструкторе нет, предполагал данный вариант, поэтому переместил создание потока в самый конец
* Этот вариант интересен, потому что при создании мини дампа средствами Win Debugging Tools, ошибка характеризуется именно как попытка установки сигнального состояния для объекта, который не является событием. Возможно, ошибка происходит где-то в ином месте и разрушает кучу. Единственный нюанс этой теории: если вынести запуск потока в отдельную функцию-член класса, т.е. вместо: new Foo(...), писать

Foo* obj = new Foo(...);
obj->init();


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

Сам я фактически перебрал все перечисленные варианты. Мне кажется, что зацепками могут являться два следующих факта:
1. При отладке внешним отладчиком при генерации исключения в пункте 3, неверными являются все поля объекта, относительно которого вызывается функция потока.
Соответственно, либо объект передается в функцию изначально испорченным (маловероятно), либо портится другими потоками во время исполнения (если так, то необходимо мне дальше самому разбираться, чтобы не выкладывать относительно много кода).
2. При выносе функции запуска потока за пределы конструктора (сейчас использую это решение) ошибка пропадает. В данном случае возникает вопрос, решена ли сама проблема, либо же она только замаскирована.

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