Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2013.09.22;
Скачать: [xml.tar.bz2];

Вниз

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

 
Pcrepair ©   (2013-01-08 17:04) [0]

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

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 через КС обращается к основному потоку. в случае обращения к объекту в основном потоке надо делать процедуру как метод класса. а в данном случае надо ли делать метод класса из обращения к ГП типа СТРОКА и к ЛЕЙБЛ на основной форме?


 
Учитель   (2013-01-08 17:15) [1]

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


 
Юрий Зотов ©   (2013-01-08 20:51) [2]

> надо ли делать метод класса из обращения к ГП типа СТРОКА и к
> ЛЕЙБЛ на основной форме?

Для таких обращений предназначен метод Syncronize.


 
Pcrepair ©   (2013-01-08 21:56) [3]

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


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

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


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


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

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

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


 
sniknik ©   (2013-01-08 22:40) [6]

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

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

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

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

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

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


 
Sha ©   (2013-01-08 22:55) [7]

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

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


 
DVM ©   (2013-01-08 23:25) [8]


> Pcrepair ©   (08.01.13 17:04) 

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

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

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


 
Pcrepair ©   (2013-01-09 17:37) [9]

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

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


 
sniknik ©   (2013-01-09 17:45) [10]

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


 
Pcrepair ©   (2013-01-09 17:57) [11]

итак, что же получается? Я вот так понял:
- для обращения к контролам формы(к примеру ЛЕЙБЛ) надо использовать 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;


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


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

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


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


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

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


 
Pcrepair ©   (2013-01-09 18:58) [14]

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


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

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

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


 
Pcrepair ©   (2013-01-09 20:10) [16]

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


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

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

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


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


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


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


 
Pcrepair ©   (2013-01-09 22:07) [19]

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


 
DVM ©   (2013-01-09 22:29) [20]


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

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

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


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


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


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


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

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

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

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


 
DVM ©   (2013-01-10 07:26) [23]


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

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


 
Pcrepair ©   (2013-01-10 14:13) [24]

и все таки не понятно. вот у меня есть ГлобПерем СТЕК
[CODE]
unit uGlobalVar;
interface
uses Classes, SysUtils, SyncObjs, Generics.Collections;
var
CS:TCriticalSection; (*используем КС для передачи результата в основной поток*)
gRestartLoadUrls:TStack<String>; (*объявляем строковый СТЕК для незакачанных УРЛ*)
implementation

initialization
  Cs:=TCriticalSection.Create;
  gRestartLoadUrls:=TStack<String>.Create(); (*создаем СТЕК типа строка*)
  gRestartLoadUrls.Clear(); (*удаляем все строки на всякий случай*)
finalization
 FreeAndNil(CS);
 FreeAndNil(gRestartLoadUrls);
end.
[/CODE]
в которую через КС потоки через gRestartLoadUrls.Add пишут свои строковые данные
по окончании цикла работы, строки накопившиеся в СТЕК потом обрабатываются в потоке, доступ опять через КС и gRestartLoadUrls.Pop

мне что то совершенно непонятно каким образом [B][COLOR="Green"]Если это не метод (не твой пользовательский метод) то сделать обертку над пуш, и перенести работу с кс внутрь ее.[/COLOR][/B]

написать процедуру с использованием СТЕК? в которой использовать КС?
желательно пример, что то о таком вообще не читал


 
DVM ©   (2013-01-10 14:47) [25]


> Pcrepair ©   (10.01.13 14:13) [24]

посмотри как сделано в классе TThreadList, вот тебе надо все то же, но вместо TList твой TStack<String>

еще как вариант, посмотреть как сделано в TThreadedQueue<T> из System.Generics.Collections и сделать по аналогии.


 
sniknik ©   (2013-01-10 15:01) [26]

> gRestartLoadUrls.Clear(); (*удаляем все строки на всякий случай*)
а "контрольное присваивание" в свою ПЕРЕМ ты случаем не делаешь? ну для гарантии, на всякий случай. :)


 
Pcrepair ©   (2013-01-10 15:13) [27]

DVM

> посмотри как сделано в классе TThreadList, вот тебе надо
> все то же, но вместо TList твой TStack<String>

вообще то TStack<String> это не мой, это стандартный объект с уже готовыми методами от RAD.
ты что ? предлагаешь отрихтовать RAD XE3? или ваабще свой класс написать?


> а "контрольное присваивание" в свою ПЕРЕМ ты случаем не
> делаешь? ну для гарантии, на всякий случай. :)

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


 
sniknik ©   (2013-01-10 15:29) [28]

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


 
DVM ©   (2013-01-10 15:39) [29]


> Pcrepair ©   (10.01.13 15:13) [27]


> вообще то TStack<String> это не мой, это стандартный объект
> с уже готовыми методами от RAD.
> ты что ? предлагаешь отрихтовать RAD XE3? или ваабще свой
> класс написать?

че там писать то?

 
 TThreadStack = class
 private
   FStack: TStack<String>;
   FLock: TObject;   // Тут в принципе крит секция может быть
 public
   constructor Create;
   destructor Destroy; override;
   function Lock: TStack<String>;
   procedure Unlock; inline;
 end;


примерно так по минимуму будет, остальное погляди в TThreadList


 
Pcrepair ©   (2013-01-10 16:21) [30]


> я тебе то же самое с потоками советовал.

всем спасибо за советы, но Я тут пока осваиваю процедурное программирование. про ООП только теорию немного почитал.


 
sniknik ©   (2013-01-10 16:26) [31]

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


 
Pcrepair ©   (2013-01-10 16:57) [32]

может еще эти...как их .. консоли изучить?
хахаха
Я изучаю программирование в среде RAD, на базе ГОТОВЫХ решений, подробно тут http://validcoderepo.narod.ru/


 
sniknik ©   (2013-01-10 18:05) [33]

> может еще эти...как их .. консоли изучить?
если "консольное" то да, а для процедурного паскаль.

> на базе ГОТОВЫХ решений
учатся на базе не решенных ЗАДАНИЙ, и самостоятельном их решении. а ты не изучаешь, ты мозги окружающим компос... ну, т.е. то что ты делаешь как то  по другому называется, только не изучение.


 
Anatoly Podgoretsky ©   (2013-01-10 18:30) [34]

Достал?


 
sniknik ©   (2013-01-10 19:55) [35]

у всего есть предел.


 
Pcrepair ©   (2013-01-10 20:25) [36]


> лучше просто отвечайте на заданные вопросы, себе же нервы
> съэкономите

Я ведь предупреждал


 
Sha ©   (2013-01-10 20:39) [37]


> Pcrepair ©   (10.01.13 16:57) [32]
> может еще эти...как их .. консоли изучить?хахахаЯ изучаю
> программирование в среде RAD, на базе ГОТОВЫХ решений, подробно
> тут http://validcoderepo.narod.ru/


Первая же "Процедура записи ошибок в ЛОГ-файл на ЖД в каталоге ЕХЕ файла"
и есть одна большая ошибка.
Подробно в учебнике.


 
Медвежонок Пятачок ©   (2013-01-10 20:56) [38]

Первая же "Процедура записи....

Похоже на сборник стёба.
Натурально так тупить невозможно.
Это лет двадцать специально учиться надо.


 
Игорь Шевченко ©   (2013-01-10 21:20) [39]


> Натурально так тупить невозможно.


Увы


 
Dimka Maslov ©   (2013-01-10 21:24) [40]


> Похоже на сборник стёба.
> Натурально так тупить невозможно.
> Это лет двадцать специально учиться надо.


Ещё как возмозжно. Но большей тупости я нигде не встречал. И двадцать лет не надо учиться, чтобы ТАК тупить.


 
Anatoly Podgoretsky ©   (2013-01-10 21:25) [41]

> Медвежонок Пятачок  (10.01.2013 20:56:38)  [38]

Откуда ты знаешь, сколько он потратил времени?


 
Pcrepair ©   (2013-01-10 23:41) [42]

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


 
Германн ©   (2013-01-11 02:16) [43]


> Pcrepair ©   (10.01.13 16:57) [32]
>
> Я изучаю программирование в среде RAD, на базе ГОТОВЫХ решений,
>  подробно тут http://validcoderepo.narod.ru/
>

"Ту-104 - самый лучший самолет!"
Поётся на мотив похоронного марша.
:)



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

Форум: "Начинающим";
Текущий архив: 2013.09.22;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.59 MB
Время: 0.003 c
15-1365397776
jimm_kerry
2013-04-08 09:09
2013.09.22
свой канал для кабельного ТВ гостиницы


2-1357713143
Crusader
2013-01-09 10:32
2013.09.22
очистка StringList


1-1314615724
denkop
2011-08-29 15:02
2013.09.22
Вопрос по отрисовке текста при TLabel.Enabled=false


15-1365885002
Юрий
2013-04-14 00:30
2013.09.22
С днем рождения ! 14 апреля 2013 воскресенье


15-1365671316
ПЛОВ
2013-04-11 13:08
2013.09.22
UDF на Delphi, FireBird и NULL





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский