| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Системное программирование и WinAPI > Использование CRT в CallBack. Чужой поток. |
| Автор: Alexeis 15.11.2010, 14:22 | ||
| Насколько я знаю, для правильного функционирования CRT в потоках требуется инициализация потока при помощи _beginthread(ex) . Т.е. дополнительно создается вот такая структура, которая хранит все глобальные переменные, которые использует CRT.
Теперь ситуация. Функция вызывается калбеком из чужого модуля (из дополнительного потока), который, не вызывал нужной _beginthread (каждый CRT, как я понимаю, требует свой _beginthread). К чему приведет в этом случае использование функций CRT? |
| Автор: Sartorius 15.11.2010, 14:32 |
| ИМХО если функции не используют общих объектов, то все Ок будет. Если используют (по комментам видно, что это за функции) то могут сработать некорректно конкурируя за данные или пытаясь посмотреть CRT контекст потока. |
| Автор: ama_kid 15.11.2010, 15:19 |
Ну, видимо, к тому, от чего призвана защитить функция _beginthreadex: всякие внутренние СRT-шные переменные типа errno,_doserrno, strtok, _wcstok, strerror и легион им подобных могут начать показывать неактуальные значения, что может привести к неуловимым глюкам, зависящим от расположения звёзд в созвездии Плеяды. |
| Автор: Sartorius 15.11.2010, 15:28 |
| Alexeis, а откуда ты beginthread взял этот? Используй CreateThread Посмотри исходники CRT. Там всякие strtok-и вызывают первым делом _getpdt. ptd создает контекст потока, если его еще нет. Все будет Ок, CRT не дураки писали. ЗЫ В общем никогда не встречал проблем с вызовом CRT функций из любых потоков. |
| Автор: Alexeis 15.11.2010, 16:08 | ||||
MSDN рекомендует обратное.
Проверил. Действительно, и билдер и студия создают блок переменных потока по первой необходимости. Единственная проблема, это утечка памяти. Вероятно следует вызвать _freeptd() по окончанию пользования этим потоком, иначе ведь возникнет утечка памяти. |
| Автор: xvr 15.11.2010, 16:11 | ||
Вот что написано в MSDN по поводу CreateProcess:
|
| Автор: Alexeis 15.11.2010, 16:23 | ||
Насколько я понял, проблема еще в том, что любое аппаратное исключение типа AV или деление на 0 приведет к краху, поскольку SEH фрейм не будет создан. Кроме того, оказывается следует вызывать не _freeptd() , а специально созданную _endthreadex() . Добавлено через 4 минуты и 11 секунд P.S. в моей ситуации SEH фрейм создаст билдер (точнее библиотеки delphi), так что этой проблемы не будет. С другой стороны будут созданы 2е копии переменных. Одна для CRT билдера, другая для CRT студии. Билдер свою почистит, а ту что создаст студия придется очищать руками. |
| Автор: Sartorius 15.11.2010, 16:36 | ||
Не совсем понял. Это почему? Любой поток содержит SEH list. Вроде ничего не мешает использвать SEH исключения |
| Автор: Alexeis 15.11.2010, 16:44 | ||
Sartorius, цитирую рихтера
Рихтер обманывать не будет. |
| Автор: GremlinProg 16.11.2010, 07:47 | ||
в принципе, нам же ни кто не мешает правильно инициализировать поток CRT:
это код из threadex.c, _initaddr - это и есть сама процедура потока но смотреть надо конечно не _callthreadstartex, а _threadstartex, в которой и происходит инициализация переменных а приоткрыть внутренние функции CRT не так и сложно, достаточно их просто объявить |
| Автор: Alexeis 16.11.2010, 11:13 | ||
| GremlinProg, такой код неприменим касательно в контексте CallBack вызовов. Как уже сказано выше, _getptd() и так вызывается по первому запросу. А блок __try{}__except(){} придется вставлять в каждую из функций обратного вызова, которые будут вызваны из дополнительного потока. Один такой блок можно организовать только внутри функции потока, а она физически расположена с другом модуле. Но это работать все равно не будет, и вот почему функция _beginthread производит инициализацию SEH для каждого потока. Без этого __try{}__except(){} будет работать неправильно. Смотрим фрагмент
Выводы следующие. 1) Вызовы CRT безопасны в функциях обратного вызова вызванных из дополнительного потока, даже если поток не создавался с _beginthread(ex). 2) Вызовы CRT в случае №1 могут приводить к утечке ресурсов, что впрочем решается дополнительным вызовом _endthreadex(), который явно освобождает ресурсы . 3) Вызовы CRT в случае №1, также не могут использовать функцию signal / __try{}__except(){}, по крайней мере до тех пор пока SEH не будет инициализирован явно. |
| Автор: GremlinProg 16.11.2010, 12:05 | ||||
ну конечно, в этом и смысл: завернуть работу CRT в твоем плагине в SEH со стандартным фильтром CRT: _XcptFilter, ничего криминального тут нет: хочешь CRT - оберни исключения в CRT-фильтр хочешь еще и переменные CRT - инициируй поток, как в _threadstartex, это и есть отправная точка любого CRT-потока, и не важно, что ты это сделаешь только в функции своей библиотеки
SEH организует _callthreadstartex в самом потоке, я же его показал, а _beginthread производит инициализацию _ptiddata, которую подчищает _endthreadex угу, смотрим, к чему он? |
| Автор: Alexeis 16.11.2010, 12:28 | ||
Это код аналогичный _threadstartex, но из билдера. Смутила фраза
И дальше идет код претендующий на полноту инициализации потока, хотя таковым не является. Полная инициализация потребует вызовов из _threadstartex и из _callthreadstartex. Причем, вероятно этот код будет непереносим на последующие версии студии. А это нехорошо. Лучше обойтись документированными средствами. |
| Автор: GremlinProg 16.11.2010, 13:30 | ||||||
это был ответ на твою последнюю цитату, ты просто сам зачем-то разделил понятия SEH с __try-__except, хотя последнее как раз этот SEH и ставит, вот я и сделал на нем акцент, раз уж тебе важно было использовать signal
именно это я и отметил
был смысл придираться? он просто ни о чем не говорит, чтобы из него еще и выводы какие-то делать, аналогий с предыдущей установкой SEH, я по крайней мере не вижу RTL exception handler - это видимо подразумевается все таки простая функция, но не SEH (билдер не использую, точнее не скажу) |
| Автор: Alexeis 16.11.2010, 14:11 | ||||
Как я понял, добавление блока __try-__except, это не тоже самое, что инициализация SEH для потока. В этом и непонятка. Почему Рихтер пишет, что функция signal будет работать неверно? Или ей для работы не хватает пресловутого первого SEH фрейма?
|
| Автор: GremlinProg 16.11.2010, 14:51 | ||||
да, потому что signal рождает исключение, перехватываемое фильтром CRT, т.е. если фильтра нет, значит соответствующие для него колбеки не будут вызваны
если бы это было так, то http://forum.vingrad.ru/index.php?showtopic=315070&view=findpost&p=2248213, между 12 и 13 строками было бы что-то, модифицирующее только что поставленный SEH, а там идет прямой вызов в пользовательскую процедуру потока |