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

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

Как правильно из потока менять Переменные в другом потоке?


Страницы:   1 2 3

Pcrepair ©   (2013-01-08 17:04:00) 

Добрый день. Есть следующий код потока

Procedure TStartTHreadLoader.BeginLoadTHreads(const Urls:string);
var
T:TStringList;
Indx1,Indx2:integer;
UrlStr:string; (*Перем для хранения УРЛ при передаче в СТЕК*)
Url:string; (*строка = УРЛ из массива*)
NumOfTHreads:integer; (*число строк с УРЛ переданное из МЕМО*)
UrlStack:TStack<String>; (*объявляем строковый СТЕК*)
begin
 T:=TStringList.Create;
 T.Text:=Urls;
   (*------------ВОПРОС1---------------------*)
     CS.Enter;  (*вход в КС*)
        try
        (*инициализация ГлобПЕрем перед циклом.
        сделать как метод класса?*)
           CurrentNumOfTHreads:=0;
        finally
           Cs.Leave;  (*выход из КС*)
        end;
  (*----------------------------------*)
  NumOfTHreads:=T.Count;

  (*---ВОПРОС2 вот тут очень криво, обращение к компонентам основной формы*)
    CS.Enter;
       try
       (*сделать вызов метода метода класса?*)
          Form1.Label2.Caption:=IntToStr(NumOfTHreads);
       finally
          Cs.Leave;
       end;
  (*---------------------------------------------------------------*)
 
    UrlStack:=TStack<String>.Create(); (*создаем СТЕК типа строка*)
     (*---ЦИКЛ ввода строк УРЛ в СТЕК-----*)
      for Indx1 := 0 to T.Count-1 do
         begin
          UrlStr:=T[Indx1];
          UrlStack.Push(UrlStr);
         end;
      (*----------------------------------*)
      (*----ЦИКЛ запуска потоков через УРЛ из СТЕК*)
      while (UrlStack.Count <> 0) do
       (*------------------------------------*)
       for Indx2 := 0 to UrlStack.Count-1 do
         begin
           if (10 > CurrentNumOfTHreads) then
             
             (*----------Вопрос 3----------------*)
             begin
               CS.Enter;
                 try
                   Inc(CurrentNumOfTHreads, 1); (*увеличиваем на +1*)
                 finally
                   Cs.Leave;
                 end;
             (*-------------------------*)
             
               if UrlStack.Count <> 0 then
               Url:=UrlStack.Pop;
               StartLoadTHread(Url); (*вызов процедуры запуска потока закачки страницы*)
               Sleep(10); (*интервал между запусками потоков*)
             end
             else Sleep(5); (*обязательно, иначе процессор вход в перегрузку*)
            (*---------------------------*)
       end;
      (*-----------------------------------------*)
  FreeAndNil(UrlStack);
  FreeAndNil(T);
end;


Внимание!!! Вопросы:
код помеченный как ВОПРОС1...3 через КС обращается к основному потоку. в случае обращения к объекту в основном потоке надо делать процедуру как метод класса. а в данном случае надо ли делать метод класса из обращения к ГП типа СТРОКА и к ЛЕЙБЛ на основной форме?


DVM   (2013-01-10 07:26:00) [21]


> Учитель   (09.01.13 22:39) [22]
> Посмотрите на TThreadList. В нем метод LockList возвращает
> ссылку
>
> Какая разница?
> Сделано иначе, но смысл один и тот же.
>

Нет не совсем одно и то же. У него то вообще плохо сделано, не спорю, но вариант с защитой каждого метода ненадежен, хотя это на первый взгляд незаметно. В интернет полно таких примеров "потокозащищенных классов"


Учитель   (2013-01-09 22:39:00) [22]

Посмотрите на TThreadList. В нем метод LockList возвращает ссылку

Какая разница?
Сделано иначе, но смысл один и тот же.
Именно метод класса занимается тем, что разруливает синхронизацию.

А у него все зависит от внимательности.
Причем дважды.
1. не забудь захватить секцию - раз.
2. не забудь захватить именно ту секцию, которую хватают другие куски кода.


Сергей М.   (2013-01-09 22:33:00) [23]


> по остальным пунктам - твое мнение?


Работу с любыми объектами синхронизации следует организовать так, чтобы было понятно что, где, как и зачем происходит. Причем понятно не только тебе, но и тому кто потенциально будет читать твой код.


DVM   (2013-01-09 22:29:00) [24]


> Учитель   (09.01.13 20:13) [17]
> Ну если до сих пор не понял, то по буквам.
> Если пуш это метод, то работу с кс перенести в метод пуш.
>

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

Посмотрите на TThreadList. В нем метод LockList возвращает ссылку на внутренний список и этот список заблокирован весь для обращения из другого потока, т.е. все его методы без исключения. Также следует поступать и с любыми другими структурами данных типа очереди, стека и т.д.


Pcrepair   (2013-01-09 22:07:00) [25]

Сергей М.
это пунк1
ну а по остальным пунктам - твое мнение?


Сергей М.   (2013-01-09 21:34:00) [26]


> для обращения к контролам формы(к примеру ЛЕЙБЛ) надо использовать
> Syncronize, только?


Не только.
Более того, в ряде случаев можно вообще обойтись без явной синхронизации.
Но в случае с TLabel она точно нужна. Как и с прочими наследниками TGraphicControl.


Учитель   (2013-01-09 20:13:00) [27]

Ну если до сих пор не понял, то по буквам.
Если пуш это метод, то работу с кс перенести в метод пуш.
Если это не метод (не твой пользовательский метод) то сделать обертку над пуш, и перенести работу с кс внутрь ее.

ТО же самое с поп.


Pcrepair   (2013-01-09 20:10:00) [28]

ГП если кто не понял значит Глобальная Переменная типа TStack<String>. в нее потоки записывают данные(строка) при определенных условиях


Учитель   (2013-01-09 19:57:00) [29]

Хоть ГП, хоть ГКЧП.

работать с КС надо внутри пуш и поп.
А не с наружи.


Pcrepair   (2013-01-09 18:58:00) [30]

и еще вопрос: запись в файл на ЖД из TStringList.SaveToFile как правильно сделать, через Синхронизация или КС?
кто нибуть в курсе?


Pcrepair   (2013-01-09 18:13:00) [31]

gRestartLoadUrls.Push  - это ГП от TStack<String>
так что не понял о чем ваабще речь


Медвежонок Пятачок   (2013-01-09 18:09:00) [32]

 CS.Enter;
   try
     gRestartLoadUrls.Push(Str); (*передаем параметр в СТЕК*)
   finally
     Cs.Leave;
   end;


А внутрь пуша работа с КС не вставлена для того, чтобы был стопудовый шанс ошибиться, забыв войти в КС перед пушем/попом?


Pcrepair   (2013-01-09 17:57:00) [33]

итак, что же получается? Я вот так понял:
- для обращения к контролам формы(к примеру ЛЕЙБЛ) надо использовать Syncronize, только?

- для обращения к переменным типа ЧИСЛО или СТРОКА можно использовать КС, причем код обращения типа
CS.Enter;
    try
      Inc(CurrentNumOfTHreads, 1); (*увеличиваем на +1*)
    finally
      Cs.Leave;
    end;


можно вставить нужном месте в коде потока, в методе Execute

- для обращения к методам объектов вне потока(например Стек.вставить), нужно написать процедуру с КС и вставить вызов этой процедуры в метод Execute потока, типа
procedure TLoader.Push(Str:string);
begin
  CS.Enter;
    try
      gRestartLoadUrls.Push(Str); (*передаем параметр в СТЕК*)
    finally
      Cs.Leave;
    end;
end;


ну че? так правильно? или опять будут возражения


sniknik   (2013-01-09 17:45:00) [34]

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


Pcrepair   (2013-01-09 17:37:00) [35]

Юрий Зотов - отдельное спасибо

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


DVM   (2013-01-08 23:25:00) [36]


> Pcrepair ©   (08.01.13 17:04) 

слушай, может тебе прекратить свои мучения потоков и посмотреть на готового робота паука на примере вот этих классов:

http://sourceforge.net/projects/alcinoe/

собственно паук тут: http://sourceforge.net/p/alcinoe/code/152/tree/demo/ALWebSpider/


Sha   (2013-01-08 22:55:00) [37]

> он не учится, он собирает набор танцев с бубном

Очень точно. Весь этот напор направлен не в ту сторону.
В арсенале кроме изрядно надоевшего TStringList появилась
еще пара "мощных" инструментов. В итоге - бег на месте.


sniknik   (2013-01-08 22:40:00) [38]

> некоторые тут советовали только КС использовать
наговариваешь? где пруфлинк?

> а вообще в каких случая использовать КС?
по обстоятельствам, где он больше подходит... не ищи что лучше (нет такого для всего), пойми как работает, и применяй по необходимости.

для синхронизации с основным потоком однозначно проще использовать Syncronize.

+
кстати я уже говорил, что вот эта хрень, тобой показанная, типа поток "диспетчер" для старта потоков, не нужна? вроде говорил.
все "счетчики" легко "ложатся" в события создания/уничтожения твоих "основных" потоков, причем эти события заранее синхронизированы... т.е. предназначены фактически под что то подобное.

++
и этот твой StartLoadTHread все что внутри меняется на 1 вызов, тоже показывал...

> Нет, он точно
он "шаман", он не учится, он собирает набор танцев с бубном, думает такие есть на все случаи...


Юрий Зотов   (2013-01-08 22:36:00) [39]


> Pcrepair ©   (08.01.13 21:56) [3]
> а вообще в каких случая использовать КС?

Не обязательно именно КС, существуют и другие способы синхронизации потоков. Она нужна, например, тогда когда несколько потоков обращаются к общим данным. Вот смотрите сами: допустим, в программе есть список каких-то объектов - что произойдет, если один поток добавляет объект в список, а другой поток в то же самое время удаляет объект из списка? Или если два потока одновременно меняют одну и ту же строку? Произойдет непонятно что, но уж точно, что ничего хорошего.

А Synchronize используется тогда, когда кусок кода нужно выполнить строго в главном потоке. В Вашем случае это обращение к компоненту TLabel на главной форме.


Учитель   (2013-01-08 22:05:00) [40]

Удалено модератором


Страницы:   1 2 3

Наверх

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