![]() |
Модераторы: Snowy, bartram, MetalFan, bems, Poseidon, Riply |
![]() ![]() ![]() |
|
Петрович |
|
||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1000 Регистрация: 2.12.2003 Где: Москва Репутация: 15 Всего: 55 |
Я тут получил в PM такой вопрос:
Решил ответить в тему. Думаю может будет многим интересно. Так вот. Есть в Delphi такой способ определения переменных. Как и следует из цитаты, переменные определенные в разделе threadvar, имееют одну роковую особенность. Для каждого созданного в программе потока, автоматически создается собственная копия такой переменной. Объявлять такие переменные можно в любом месте где разрешено объявлять глобальные переменные. Т.е. вне пределов процедур или функций. Это и понятно, ведь локальные переменные определяемые внутри процедур и функций размещаются в стеке, а он у каждого потока свой. Так что локальный threadvar, это нонсенс. Теперь, немного о том зачем они нужны, и как их используют. Опять-же, как сказано в цитате, обычно данные, локальные для потока, удобно размещать в полях объекта tThread. Но, не всегда это возможно. Вот нескоько ситуаций. 1. Если поток создается средствами API, без применения Delphi'йского объекта tThread, то локальные данные потока можно разместить только в стеке, т.е. локальные переменные. Но, такой способ предполагает что все процедуры и функции использующие эти данные должны быть вложенными по отношению к процедуре потока. Это сильно затрудняет написание программы. Можно конечно и по другому. Создать в динамической памяти структуру (объект), и при вызове из процедуры потока других, не вложенных процедур, передавать в них указатель на эту структуру. Впротчем, именно так и происходит с классом tThread ![]() Вот здесь и приходит на помощь threadvar. Можно просто объявить переменную в разделе threadvar. Это будет обычная глобальная переменная, но т.к. для каждого потока она своя, то и не будет проблем при запуске нескольких потоков ее использующих. 2. Даже если мы адепты Delphi, и все наши потоки наследуются от tThread, то нам все равно может пригодиться threadvar. Продемонстрирую это на примере собственного использованя. Есть у меня такой модуль awLog. Он экспортирует набор процедур предназначенных для ведения файла протокола. Естественно, процедуры этого модуля могут вызываться в контексте любого потока. Соответственно, есть программа которая обслуживает запросы удаленных клиентов - серверок такой. При подключении клиента к серверу, для его обслуживания создается индивидуальный поток. Тело потока для всех потоков одно, в смысле имеется единственный тип tThread, и для каждого пользователя создается собственный экземпляр этого типа. В процессе обслуживания, вызываются процедуры записи в протокол. Если не предпринять специальных действий, то в протоколе получится каша, в которой нет никакой возможности определить к какому клиенту относится та или иная запись. Можно конечно добавить в процедуры протоколирования еще один параметр - имя клиента. И каждый раз, при вызове, передавать туда соответствующее значение. Но, модуль протоколирования у меня библиотечный, а по этому должен быть универсальным. Я его использую и в однопоточных приложениях. Выход есть. Я определил в модуле awLog threadvar-переменную UserName. Любой поток, может занести туда имя обслуживаемого в данный момент клиента. А все процедуры протоколирования, берут оттуда значение вставляемое в начало каждой строки протокола. Если же приложение однопоточное, то оно может в UserName ничего не заносить. Оно вообще может не знать о ее существовании. 3. Опять же есть библиотечный модуль для работы и Interbase-сервером через API. Его структура такова, что там есть необходимость использования глобальной переменной статуса завершения операции. Не хорошо конечно, но увы, без глобалов не всегда можно обойтись. По крайней мере не потеряв эффективность и наглядность программы. Но, применение глобалов это обычно приговор: "не реентерабельно!". Т.е. использовать процедур общающиеся между собой через глобалы в мультипоточном приложении недопустимо! Но, если эти глобалы сделать не var-переменными, а threadvar-переменными, то все будет в порядке. Вот поэтому, в упомянутом мною библиотечном модуле, переменная статуса завершения операции определена в разделе threadvar. Думаю, теперь стало ясно как и зачем нужны threadvar-переменные. Но, это еще не все. Казалось бы, найдено "петушиное слово". Теперь, мы все глобальные переменные описываем не как var, а как threadvar, и проблемма нереентерабельности библиотечных процедур решена навеки. Увы, не все так радужно. Дело в том, что механизм реализации threadvar-переменных таков, что обращение к ним обходится чувствительно дороже, нежели обращение к обычным глобальным переменным. Поэтому, не стоит их применять направо и налево. В общем, я рекомендую не злоопутреблять ими, а применять их только в тех случаях, где без них просто не обойтись. И еще. Это важно. Есть некоторые ограничения использования threadvar-переменных. 1. Эти переменные не могут иметь тип Pointer или тип procedure/function 2. threadvar-переменные типов имеющих так называемую copy-on-write логику, могут работать некорректно. Наиболее яркими представителями таких типов являются "длинные" строки и динамические массивы. Их использования для threadvar-переменных нежелательно. По крайней мере, так сказано в Help'е. Лично я с этим не согласен ![]() Вот теперь вроде все. -------------------- Все знать невозможно, но хочется |
||||
|
|||||
![]() ![]() ![]() |
Правила форума "Delphi: WinAPI и системное программирование" | |
|
Запрещено: 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, bartram, MetalFan, bems, Poseidon, Rrader, Riply. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Delphi: WinAPI и системное программирование | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |