Модераторы: Poseidon, Snowy, bems, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Защищены ли переменные в TThread, от одновременного доступа? 
V
    Опции темы
Ibragim
Дата 18.12.2006, 16:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 177
Регистрация: 28.9.2004
Где: Киев

Репутация: нет
Всего: нет



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

Реализована ли защита переменных от одновременного доступа в TThread средствами самого TThread? Или нужно самому реализовавать? 

Есть вероятность чтения переменной а одновременно разными потоками. Можно ли делать так 
Код

TA = class(TThread)
  a: integer;
end;


или нужно так

Код

  property a: integer read GetA write SetA;
....
function GetA: integer;
begin
  MyCriticalSection.Enter;
  result := a;
  MyCriticalSection.Leave;
end;



Спасибо за ответ на наверняка уже звучавший вопрос.
PM MAIL   Вверх
Romikgy
Дата 18.12.2006, 17:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Любитель-программер
****


Профиль
Группа: Участник Клуба
Сообщений: 7326
Регистрация: 11.5.2005
Где: Porto Franco Odes sa

Репутация: 26
Всего: 146



Цитата(Ibragim @  18.12.2006,  15:57 Найти цитируемый пост)
или нужно так

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


--------------------
Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. 
smile

PM   Вверх
Sansa
Дата 18.12.2006, 17:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 173
Регистрация: 18.10.2006
Где: Королев

Репутация: 3
Всего: 6



Чтение переменной разными потоками не приведет к коллизиям. Главное чтоп не было одновременной записи
--------------------
- Здравствуйте, я Ваш патологоанатом
PM MAIL ICQ   Вверх
Snowy
Дата 18.12.2006, 17:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 11363
Регистрация: 13.10.2004
Где: Питер

Репутация: 192
Всего: 484



Переменная a у каждого треда будет своя собственная.
Никаких коллизий не будет, если только ты не попытаешься обратиться к переменной а одного треда из другого прямым указанием.
PM MAIL   Вверх
Ibragim
Дата 18.12.2006, 17:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 177
Регистрация: 28.9.2004
Где: Киев

Репутация: нет
Всего: нет



Snowy,  Это я и имел в виду, когда писал "Есть вероятность чтения переменной а одновременно разными потоками".  То есть другие потоки, положим TB = class(TThread), будут читать переменную у этого объекта (у ОДНОГО объекта класса TThread), может случиться что и одновременно.

Sansa,  а если один читает а другой пишет?
PM MAIL   Вверх
Snowy
Дата 18.12.2006, 17:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 11363
Регистрация: 13.10.2004
Где: Питер

Репутация: 192
Всего: 484



Тогда защищать обязательно.
PM MAIL   Вверх
Sansa
Дата 18.12.2006, 17:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 173
Регистрация: 18.10.2006
Где: Королев

Репутация: 3
Всего: 6



Ibragim, че-та я сегодня рассеяный немного. Не обратил внимание, что это член класса. Мой ответ применим к глобальной переменной. И если один пишет, а другой читает (глобальную переменную или член класса объявленного вне TThread'ов), то тоже коллизий не произойдет. Но если один ВСЕГДА ТОЛЬКО ПИШЕТ, а второй ВСЕГДА ТОЛЬКО ЧИТАЕТ
--------------------
- Здравствуйте, я Ваш патологоанатом
PM MAIL ICQ   Вверх
Snowy
Дата 18.12.2006, 18:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 11363
Регистрация: 13.10.2004
Где: Питер

Репутация: 192
Всего: 484



Sansa, нельзя так.
Ошибок не будет, но будет вероятность получения неактуальных данных.
То есть мы получим устаревшее значение.
Один тред возьмёт это значение, второй его изменит, а первый продолжит работать со старым значением, не подозревая, что оно уже неверное.
PM MAIL   Вверх
Ibragim
Дата 18.12.2006, 18:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 177
Регистрация: 28.9.2004
Где: Киев

Репутация: нет
Всего: нет



Гуд, общая идея понятна. Мнение - защищать. Так и будем делать. Всем спасибо, тема закрыта.

PS Тля, у меня штук пятьдесят таких переменных! Счас copy-paste все переделать в property и сделать на них CriticalSection's - бррр, ну пошел работать.
PM MAIL   Вверх
Sansa
Дата 19.12.2006, 16:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 173
Регистрация: 18.10.2006
Где: Королев

Репутация: 3
Всего: 6



Ibragim, скачай JCL и загляни в модуль JclSynch.pas. Там найдешь много полезных функций именно по локам, например: 
Код

// Routines to manipulate simple typed variables in a thread safe manner
function LockedAdd(var Target: Integer; Value: Integer): Integer;
function LockedCompareExchange(var Target: Integer; Exch, Comp: Integer): Integer; overload;
function LockedCompareExchange(var Target: Pointer; Exch, Comp: Pointer): Pointer; overload;
function LockedDec(var Target: Integer): Integer;
function LockedExchange(var Target: Integer; Value: Integer): Integer;
function LockedExchangeAdd(var Target: Integer; Value: Integer): Integer;
function LockedExchangeDec(var Target: Integer): Integer;
function LockedExchangeInc(var Target: Integer): Integer;
function LockedExchangeSub(var Target: Integer; Value: Integer): Integer;
function LockedInc(var Target: Integer): Integer;
function LockedSub(var Target: Integer; Value: Integer): Integer;


И ничего копи-пастить не надо.


Snowy, простой блокировкой от неактуальности в асинхронных процессах не избавишься, все зависит от задачи. Если выполняется простое действие типа 
Код
 SomeInteger:= ThreadInteger + AnotherInteger
, то даже с устаревшими данными ничего не сломается. А вот данная конструкция 
Код
 SomeInteger:= ThreadInteger + AnotherInteger; SomeDouble:= ThreadInteger * AnotherInteger
 (двойное последовательное обращение) что с блокировкой, что без, хоть и может привести к краху, но легко обходится временной переменной.

Если надо твердо определять актуальность данных, то необходимы более сложные алгоритмы. Например, как в OPC используются дополнительные поля Timestamp (когда изменилось) и Quality (не было ли ошибок при пересчете).

Это сообщение отредактировал(а) Sansa - 19.12.2006, 16:21
--------------------
- Здравствуйте, я Ваш патологоанатом
PM MAIL ICQ   Вверх
Snowy
Дата 19.12.2006, 16:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 11363
Регистрация: 13.10.2004
Где: Питер

Репутация: 192
Всего: 484



Цитата(Sansa @  19.12.2006,  16:20 Найти цитируемый пост)
 SomeInteger:= ThreadInteger + AnotherInteger
Это только кажется простоым.
На самом деле всё далеко не так просто.
Вспомни хотя бы про interlocked. Они не спроста придуманы smile
Например, наша переменная - это счётчик.
Мы хотим сделать:
Код
  с := c +1; // либо inc(c);
Компилируем. Получаем
Код
mov eax, [c]
inc eax
mov [c], eax
Что же случится, если после выполнения первой комманды управление перейдёт другому треду? Он изменит c, а мы снова запишем в него "наше" значение, а не верное smile

Цитата(Sansa @  19.12.2006,  16:20 Найти цитируемый пост)
но легко обходится временной переменной.
Опять же пример - у нас счётчик. Мы должны к нему добавить еденичку.
По приведённому выше примеру видно, что в результате мы прибавим одну еденичку, а не две.
И эта ошибка будет нестабильной, проявляясь в то время, когда не надо, а не когда мы её ловим smile
PM MAIL   Вверх
Sansa
Дата 19.12.2006, 18:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 173
Регистрация: 18.10.2006
Где: Королев

Репутация: 3
Всего: 6



Я особо выделил, что для того, чтобы не надо было использовать локи, переменная должна изменяться в одном месте, а у тебя в примере получается в 2-х. Если мы прибавляем 1 в одном потоке, а во втором в это время читаем эту переменную, то все казусы - это то, что мы не будем точно знать увеличенное или нет у нас взято значение вторым потоком. Но локи тут не помогут. Мы будем лишь твердо уверены в том, что мы взяли переменную либо до выполнения этой строки (c:= c+1) либо после, но никак не во время. Это мало что дает на практике.

Яркий пример того, что я имел в виду: 
Есть поток, который 100 раз в секунду получает значение (скажем температуры) с СОМ порта, и записывает ее в глобальную переменную. Второй поток с частотой того же порядка  (скажем 90 Гц) читает эту переменную и выполняет какие-то операции в зависимости от ее значения. И есть 3-й поток, который раз в секунду читает это же значение и отображает его на экране. Без локов программа будет работать даже эффективнее, так как при их использовании и критичных ко времени алгоритмах (или высоких частотах опроса переменной) могут возникать таймауты, так как потоки будут тратить время на ожидание друг друга.
--------------------
- Здравствуйте, я Ваш патологоанатом
PM MAIL ICQ   Вверх
Romikgy
Дата 19.12.2006, 19:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Любитель-программер
****


Профиль
Группа: Участник Клуба
Сообщений: 7326
Регистрация: 11.5.2005
Где: Porto Franco Odes sa

Репутация: 26
Всего: 146



Цитата(Sansa @  19.12.2006,  17:00 Найти цитируемый пост)
Яркий пример того, что я имел в виду: 
Есть поток, который 100 раз в секунду получает значение (скажем температуры) с СОМ порта, и записывает ее в глобальную переменную. Второй поток с частотой того же порядка  (скажем 90 Гц) читает эту переменную и выполняет какие-то операции в зависимости от ее значения. И есть 3-й поток, который раз в секунду читает это же значение и отображает его на экране. Без локов программа будет работать даже эффективнее, так как при их использовании и критичных ко времени алгоритмах (или высоких частотах опроса переменной) могут возникать таймауты, так как потоки будут тратить время на ожидание друг друга.

данный пример , имхо проще сделать используя сообщения безопаснее!


--------------------
Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. 
smile

PM   Вверх
Sansa
Дата 20.12.2006, 11:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 173
Регистрация: 18.10.2006
Где: Королев

Репутация: 3
Всего: 6



Согласен. И с точки зрения ООП - грамотнее. Но это надо мутить контроллер, который будет раздавать всем зарегистрированым "потребителям сего значения" сообщения о его изменении, причем с указанным для каждого из них таймаутом.
--------------------
- Здравствуйте, я Ваш патологоанатом
PM MAIL ICQ   Вверх
Snowy
Дата 20.12.2006, 11:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 11363
Регистрация: 13.10.2004
Где: Питер

Репутация: 192
Всего: 484



Пример всего дишь для того, чтобы показать, что защищать надо.
Можно придумывать ситуации, когда это не очень важно или не так страшно.
Но лучше защищать всегда.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

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

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1311 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.