Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.03.25;
Скачать: CL | DM;

Вниз

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

 
SpellCaster   (2007-02-26 12:37) [0]

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


 
clickmaker ©   (2007-02-26 12:42) [1]

критические секции юзай
потому как то, что ты читаешь, в этот же момент кто-то может менять


 
Сергей М. ©   (2007-02-26 12:42) [2]


> действителдьно ли юзать переменные в нитях неправильно?


Неправильна сама постановка вопроса о "неправильности".
Правильно или неправильно - это зависит от полного понимания происходящего при этом.


> чем это может грозить?


Минимум - "глюками".
Максимум - крахом нити и/или процесса.


 
DrPass ©   (2007-02-26 12:58) [3]


> Я-то всегда считал, что их можно беспрепятственно применять,
>  если производится только чтение

Если речь идет об атомарной переменной (операции с которыми делаются "за один заход"), то можно - ничего с ней не сделается во время чтения. Со сложными типами следует быть осторожнее, тут уже все от логики приложения зависит. Если для чтения следует выполнить много операций, и есть другие потоки, которые могут что-либо писать туда - это действительно чревато ошибками.


 
Степан   (2007-02-26 17:41) [4]

А какой лучший способ взаимодействия главного и побочного потоков? Я, например, использовал только PostMessage. Может есть другие способы?


 
Игорь Шевченко ©   (2007-02-26 17:46) [5]


> А какой лучший способ взаимодействия главного и побочного
> потоков?


Рихтер целую главу (может, и не одну) написал про механизмы взаимодействия потоков в книжке "Windows для профессионалов". Может, его почитать ?


 
Anatoly Podgoretsky ©   (2007-02-27 00:25) [6]

> SpellCaster  (26.02.2007 12:37:00)  [0]

> Я-то всегда считал, что их можно беспрепятственно применять, если производится только чтение,

Это уже константа, а не переменная.


 
SpellCaster   (2007-02-28 11:23) [7]

Поясняю ситуацию. Есть некий набор переменных, представляющий собой настройки проги. Они меняются только после закрытия формы настроек, в процессе работы проги они постоянны. По-моему, юзать их в потоках вполне безопасно - или я не прав? Просто критикалы или синхрониз юзать на каждое применение переменной не хочется. Можно, конечно, скопировать настройки в локальные переменные потока, но это тоже замороченный метод.


 
SpellCaster   (2007-02-28 11:26) [8]

Кстати, а можете просветить вкратце: в чём собственно сама проблема наложения чтения/записи? Ведь в конечном итоге процессор всё равно выполняет только одну операцию в каждый конкретный момент времени.


> [5] Игорь Шевченко ©   (26.02.07 17:46)

А есть ссылочка?


 
Сергей М. ©   (2007-02-28 11:30) [9]


> Ведь в конечном итоге процессор всё равно выполняет только
> одну операцию в каждый конкретный момент времени.


Присвоение значения строковой переменной - это далеко не одна процессорная операция.


 
DrPass ©   (2007-02-28 11:32) [10]


> Кстати, а можете просветить вкратце: в чём собственно сама
> проблема наложения чтения/записи? Ведь в конечном итоге
> процессор всё равно выполняет только одну операцию в каждый
> конкретный момент времени.

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


 
Tor ©   (2007-02-28 12:01) [11]

Сцуть заключается в следующем, нельзя читать когда пишут. Если настройки меняются тока впи закрытии окна, ну так останови поток запиши и двигай дальше. А вообще 10-раз обдумай целесообразность многопоточности, т.к. это сильно усложняет код проги, хотя по началу это не заметно. в конце концов критические секции это не долго. :)


 
SpellCaster   (2007-02-28 13:08) [12]

> [9] Сергей М. ©   (28.02.07 11:30)


> [10] DrPass ©   (28.02.07 11:32)

Да, про строковые как-то не подумал.

> [11] Tor ©   (28.02.07 12:01)

Наверно, так и сделаю - приостановлю потоки на время изменения натсроек. Многопоточность нужна, т.к. это сетевое приложение, там куча всего качается и отсылается. С потоками раньше особо работать не приходилось, только на Яве, но на Яве это всё так завуалировано, что можно не париться про взаимодействие.


 
SpellCaster   (2007-02-28 13:32) [13]

И еще вопросик про критические секции. Насколько я понял, покопавшись в сорсах VCL, их можно применять в любой процедуре. Вот такой способ - нормально?

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

...

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


Также я не понял, какой смысл лочить в следующем фрагменте

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;


 
Сергей М. ©   (2007-02-28 14:05) [14]


> SpellCaster   (28.02.07 13:32) [13]


А что тебя так заклинило именно на глоб.переменных ?
Существует масса иных способов заставить поток изменить хот выполнения алгоритма..


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

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

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


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


> SpellCaster   (28.02.07 15:21) [15]


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


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

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

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


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

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 17:57) [19]

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

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


 
evvcom ©   (2007-03-01 10:51) [20]

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

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


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


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


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


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

> [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 - класс, хранящий настройки.


 
evvcom ©   (2007-03-01 11:20) [23]

> [22] SpellCaster   (01.03.07 11:14)

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


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


> SpellCaster   (01.03.07 11:14) [22]


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

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


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

> [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 14:42) [26]


> SpellCaster   (01.03.07 14:34) [25]



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


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


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


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

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


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

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

Да.

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

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


 
evvcom ©   (2007-03-01 15:52) [28]


> [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;


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


> SpellCaster   (01.03.07 15:24) [27]


> Да.


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


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


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

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

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

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


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


> SpellCaster   (01.03.07 15:24) [27]


> Да.


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


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


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

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

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

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


 
evvcom ©   (2007-03-01 16:05) [31]

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

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


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

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

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

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


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

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

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


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


> SpellCaster   (01.03.07 16:47) [32]


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


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


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


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

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

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


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

> Не будет.

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

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


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

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



Страницы: 1 вся ветка

Текущий архив: 2007.03.25;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.039 c
15-1172357538
Help!!!
2007-02-25 01:52
2007.03.25
По вечерам изображение на мониторе начинает дёргаться С чем может


15-1172478724
ocean
2007-02-26 11:32
2007.03.25
Windows installer error


10-1130395613
Тёма
2005-10-27 10:46
2007.03.25
ActiveX-компонент в word e без OCX


2-1172846889
Ezorcist
2007-03-02 17:48
2007.03.25
Реакция на выключение и на убийство по ctrl+alt+del


2-1172939940
Roman_S
2007-03-03 19:39
2007.03.25
Как узнать размер каталога по пути?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский