Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Глобальные переменные в нитях


Страницы:   1 2

SpellCaster ©   (2007-02-26 12:37:00) 

Всем привет! Просветите, пожалуйста, насчёт использования глобальных переменных в нитях. Я-то всегда считал, что их можно беспрепятственно применять, если производится только чтение, но почитал одну ветку здесь и засомневался. Так действителдьно ли юзать переменные в нитях неправильно? А чем это может грозить?


SpellCaster   (2007-03-01 18:49:00) [1]

> Не будет.

ОК, согласен. Но идея юзать критикалы для обращения к переменным как-то не очень прельщает...

Насчет threadvar: что-то с ними тоже какая-то засада. По крайней мере, строка не передавалась в функцию основного потока... ладно, сделал через внутренние переменные нити.


> Что вообще тебе мешает передать значение настройки параметром
> в конструктор потока ?

Да ничего, в общем-то... кроме того факта, что придётся делать ещё и процедуру апдейта этих настроек, поскольку они могут поменяться во время работы нити.


Сергей М.   (2007-03-01 16:56:00) [2]


> SpellCaster   (01.03.07 16:47) [32]


> Тормозить будет


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


> при создании потока буду копировать нужные настройки в локальные
> threadvar. Уж они-то, вроде бы, безопасны?


Хрен редьки не слаще)

Безопасны-то они безопасны, но предназначены совсем для другой цели и работают они по-другому.

Что вообще тебе мешает передать значение настройки параметром в конструктор потока ?


SpellCaster   (2007-03-01 16:47:00) [3]

> [28] evvcom ©   (01.03.07 15:52)
Так как в основном потоке идет визуализация добавленных тобой строк, а значит и чтение, которым управлять ты в полной мере не можешь.

Ладно, ладно, не стану морочиться, действительно сделаю как делал раньше - с двумя методами и synchronize.
> [29] Сергей М. ©   (01.03.07 16:01)
> Тогда использование крит.секции - верный совет и верное
> решение.

Хммм... только не в моем случае. Тормозить будет, да и много лишних строк получится.


> Вот смотри и вникай:

Ага. Посмотрел, проникся. Зарёкся юзать какие-либо межпотоковые переменные вообще )).

Наверно, просто при создании потока буду копировать нужные настройки в локальные threadvar. Уж они-то, вроде бы, безопасны?


evvcom   (2007-03-01 16:05:00) [4]

> [30] Сергей М. ©   (01.03.07 16:02)

Не... Это в лучшем случае программист при тестировании получит AV, а в худшем 'ABF' он не заметит и отправит прогу пользователю. :)


Сергей М.   (2007-03-01 16:02:00) [5]


> SpellCaster   (01.03.07 15:24) [27]


> Да.


Тогда использование крит.секции - верный совет и верное решение.


> Если нить приостановлена, то она и не обращается ни к каким
> переменным, верно?


Вот смотри и вникай:

Некая нить в момент времени M начала чтение длинной строки, на этот момент содержимое строки равно, скажем, 'AВС'

В момент времени N некая другая нить, приостановив первую нить (которая успела прочитать на этот момент только первые 2 символа строки, т.е. 'АВ'), пишет в длинную строку 'DEF' и возобновляет работу первой нити.

Что в рез-те получит первая нить ?
Да cолянку сборную она получит в виде 'ABF' ! Хотя ожидалась либо 'ABC' либо  'DEF'.. И это - в лучшем случае ... А в худшем читающая нить возбудит AV-исключение


Сергей М.   (2007-03-01 16:01:00) [6]


> SpellCaster   (01.03.07 15:24) [27]


> Да.


Тогда использование крит.секции - верный совет и верное решение.


> Если нить приостановлена, то она и не обращается ни к каким
> переменным, верно?


Вот смотри и вникай:

Некая нить в момент времени M начала чтение длинной строки, на этот момент содержимое строки равно, скажем, 'AВС'

В момент времени N некая другая нить, приостановив первую нить (которая успела прочитать на этот момент только первые 2 символа строки, т.е. 'АВ'), пишет в длинную строку 'DEF' и возобновляет работу первой нити.

Что в рез-те получит первая нить ?
Да cолянку сборную она получит в виде 'ABF' ! Хотя ожидалась либо 'ABC' либо  'DEF'.. И это - в лучшем случае ... А в худшем читающая нить возбудит AV-исключение


evvcom   (2007-03-01 15:52:00) [7]


> [25] SpellCaster   (01.03.07 14:34)
> Ага, ясно. Т.е. если из мемо ничего не считывать, то в принципе
> это прокатит

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

> form1.msg:=s;
> synchronize(form1.log);

Обычно делают проще.
proc thread.Execute;
begin
...
msg := s;
synchronize(log);
...
end;

proc thread.Log;
begin
form1.memo1.lines.add(msg);
end;


SpellCaster   (2007-03-01 15:24:00) [8]

> В этот момент другие потоки, обращающиеся к этому св-ву,
> существуют ?

Да.

> Хреновый совет.

Ну почему же? Если нить приостановлена, то она и не обращается ни к каким переменным, верно?


Сергей М.   (2007-03-01 14:42:00) [9]


> SpellCaster   (01.03.07 14:34) [25]



> В основном, после нажатия кнопки ОК на форме настроек


В этот момент другие потоки, обращающиеся к этому св-ву, существуют ?


> сделал, как советовал Tor


Хреновый совет.

С Boolean-данными это еще худо-бедно прокатит, но стоит применить сей способ для, к примеру, длинных строк - тут же схлопочешь те же самые вышеупомянутые грабли.


SpellCaster   (2007-03-01 14:34:00) [10]

> [23] evvcom ©   (01.03.07 11:20)

Ага, ясно. Т.е. если из мемо ничего не считывать, то в принципе это прокатит - опасность начинается, когда начинаем работать с мемо из главной формы?
Хорошо, а как такой способ:

procedure thread.log(s: string);
begin
logger.enter;
form1.msg:=s;
synchronize(form1.log);
logger.leave;
end;

procedure form1.log;
begin
memo1.lines.add(msg);
end;

Критикал тут для того, чтобы другой поток в это время не трогал msg. Так верно будет?

> [24] Сергей М. ©   (01.03.07 11:21)

В основном, после нажатия кнопки ОК на форме настроек. Я сделал, как советовал Tor: ставлю все нити на паузу, обновляю настройки, а потом запускаю.


Сергей М.   (2007-03-01 11:21:00) [11]


> SpellCaster   (01.03.07 11:14) [22]


Т.е. Settings - это глобальная переменная типа TSomeClass ?

Тогда поясни, в каком потоке и в какой момент времени осуществляется модификация св-ва Network_ConnectTry ..


evvcom   (2007-03-01 11:20:00) [12]

> [22] SpellCaster   (01.03.07 11:14)

Ах, вот оно что! Нельзя так делать. Своим Logger.Enter/Leave ты синхронизируешь только добавление строк в мемо из твоих потоков, вызывающих твой Log. Но ты забываешь, что при добавлении строки внутри этого Add происходит много различных действий, в том числе и перевыделение памяти под стринг, которое никак не синхронизировано с чтением в основном потоке. Используй Synchronize.


SpellCaster   (2007-03-01 11:14:00) [13]

> [20] evvcom ©   (01.03.07 10:51)

Наверно, я непонятно написал... это просто заголовок метода Execute. Вот так вернее будет:

procedure TmyThread.Execute;
begin
...
Log('Hi');
...
end;



> [21] Сергей М. ©   (01.03.07 10:57)

Не, в этом коде переменных нету, это я уже про крит.секции спросил. А с переменными вот фрагмент:

...
  Inc(CurrTry);
  if CurrTry=Settings.Network_ConnectTry then
  begin
   WriteLog(Format('%d неудачных попыток - ждём %d сек.',
            [Settings.Network_ConnectTry,Settings.Network_RetryInterv]),mkProc);
   Sleep(Settings.Network_RetryInterv*1000);
   CurrTry:=0;
  end;
...

Settings - класс, хранящий настройки.


Сергей М.   (2007-03-01 10:57:00) [14]


> что скажешь насчет [13]?


Какая переменная у тебя в этом коде глобальная ?


evvcom   (2007-03-01 10:51:00) [15]

> [13] SpellCaster   (28.02.07 13:32)
> ...Thread.Execute...

Что это вообще такое? Этот вызов за тебя уже сделает VCL. Не надо нарушать правила, чтобы твой код был логичен и понятен.


SpellCaster   (2007-02-28 17:57:00) [16]

jack128
1) Хм. Что-то я не догоняю. Это процедура, которая вызывается из других нитей. А почему неправильно? И как правильно? Logger объявлен в главном модуле.

2) FSocket, как я понял, приватная переменная, и вроде бы не должна меняться в другой нити. Хотя кто их знает, борландовцев, что у них в голове - может, они специально сделали thread-safe класс.


jack128   (2007-02-28 17:44:00) [17]

SpellCaster   (28.02.07 13:32) [13]
Вот такой способ - нормально?

procedure Log(s: string);
begin
Logger.Enter;
try
FormMain.Memo1.Lines.Add(s);
finally Logger.Leave; end;
end;

...

...Thread.Execute...
...
Log('Hi');
...
end


Если это выполняется НЕ в основном потоке - то нет.

SpellCaster   (28.02.07 13:32) [13]
Также я не понял, какой смысл лочить в следующем фрагменте

function TCustomWinSocket.GetLocalAddress: string;
var
SockAddrIn: TSockAddrIn;
Size: Integer;
begin
Lock; // синоним Critical.Enter
try
  Result := '';
  if FSocket = INVALID_SOCKET then Exit;
  Size := SizeOf(SockAddrIn);
  if getsockname(FSocket, SockAddrIn, Size) = 0 then
    Result := inet_ntoa(SockAddrIn.sin_addr);
finally
  Unlock; // синоним Critical.Leave
end;
end;


если FSocket меняется ТОЛЬКО в том же потоке, в котором выполняется этот код, то лочить естественно ничего не надо..


SpellCaster   (2007-02-28 16:21:00) [18]

> [16] Сергей М. ©   (28.02.07 15:29)

ЗнаешЬ, может, я действительно туплю по-страшному, но не представляю совершенно. Так что скажешь насчет [13]?


Сергей М.   (2007-02-28 15:29:00) [19]


> SpellCaster   (28.02.07 15:21) [15]


ты даже не представляешь. какую глупость ты сейчас сморозил)


SpellCaster   (2007-02-28 15:21:00) [20]

> [14] Сергей М. ©   (28.02.07 14:05)

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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо