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

Вниз

Как выводить статус от нескольких потоков?   Найти похожие ветки 

 
MegaVolt ©   (2006-03-02 16:29) [0]

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


 
Crash Coredump ©   (2006-03-02 16:30) [1]

Не наблюдал тормозов при использовании Synchronize


 
DesWind ©   (2006-03-02 16:37) [2]

через сообщения или по таймеру на форме обновлять инфу о потоках


 
Сергей М. ©   (2006-03-02 16:42) [3]

синхронизировать только те операции, которые обновляют виз.контролы на целевой форме.


 
MegaVolt ©   (2006-03-02 16:46) [4]

Я не совсем Synchronize использую. Я использовал TThreadList для обмена. Но получил то что форма при перетаскивании уже ощутимо дергается :(


 
Сергей М. ©   (2006-03-02 16:49) [5]

Код приводи


 
MegaVolt ©   (2006-03-02 16:58) [6]

Записываю в потоке сообщение так:


FLogs:String;
property Logs:String write SaveLog;
procedure SaveLog(const Value: String);
procedure SaveLogs;

procedure TScanIP.SaveLog(const Value: String);
begin
 FLogs:=Value;
 Synchronize(SaveLogs);
end;

procedure TScanIP.SaveLogs;
var
 i:integer;
begin
 with Form1.ListThead.LockList do
   try
     for i:=Count-1 downto 0 do
       if (PTheadItem(Items[i])^.IP)=IP
         then
           begin
             PTheadItem(Items[i])^.Log:=FLogs;
             break;
           end;
   finally
     Form1.ListThead.UnlockList;
   end;
end;


вычитываю так:


procedure TForm1.ListView1Data(Sender: TObject; Item: TListItem);
begin
 with ListThead.LockList do
   try
     if Item.Index<Count
       then
         begin
           Item.Caption:=IPToStr(PTheadItem(Items[Item.Index])^.IP);
           Item.SubItems.Add(SecToFTime(Round((GetTickCount-PTheadItem(Items[Item.Index])^.Start)/1000)));
           Item.SubItems.Add(PTheadItem(Items[Item.Index])^.Log);
         end
       else
         begin
           Item.Caption:="";
           Item.SubItems.Add("");
           Item.SubItems.Add("");
         end;
   finally
     ListThead.UnlockList;
   end;
end;


 
MegaVolt ©   (2006-03-02 17:13) [7]

Хм... Заремил всё а тормоза остались :( Видать много потоков как то всё же тормозят сами по себе.


 
MegaVolt ©   (2006-03-02 17:21) [8]

Возможно при такой организации Synchronize не нужен? Т.е. в любом потоке я обращаюсь к TThreadList и всё будет работать так как нужно?


 
Гаврила ©   (2006-03-02 17:31) [9]


> MegaVolt ©

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


 
Leonid Troyanovsky ©   (2006-03-02 17:33) [10]


> MegaVolt ©   (02.03.06 17:21) [8]
> Возможно при такой организации Synchronize не нужен? Т.е.
>  в любом потоке я обращаюсь к TThreadList и всё будет работать
> так как нужно?


Скорее, наоборот. Т.е., TThreadList не нужен, а нужен простой synchronize.
Ну, а для ускорения лучше взять не ListView, а, скажем, TStatusBar.

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2006-03-02 17:39) [11]


> Гаврила ©   (02.03.06 17:31) [9]

> Я аналогичную задачу выполняю так - отправляю пост-мессаджи


PostMessage строки (string) опасно.
А вот SendMessage - вполне, скажем, to StaticText.
Дешево и сердито.

--
Regards, LVT.


 
MegaVolt ©   (2006-03-02 17:56) [12]

>TThreadList не нужен
он исспользуется не только для этого так что пока пусть будет.

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

>а для ускорения лучше взять не ListView, а, скажем, TStatusBar.
А если мне нужно отображать статус от каждого потока? Да и что либо быстрее ListView в виртуальном режиме я не встречал пока :)

>А вот SendMessage
Можно чуть поподробней или примерчик. Я с этим не очень сталкивался. Ведь поток тоже будет ждать пока будет обработан SendMessage. В чём выигрышь.


 
Leonid Troyanovsky ©   (2006-03-02 18:00) [13]


> MegaVolt ©   (02.03.06 17:56) [12]
> >TThreadList не нужен
> он исспользуется не только для этого так что пока пусть
> будет.


Если он используется аналогично, то вопрос об его
нужности еще более значим.

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2006-03-02 18:04) [14]


> MegaVolt ©   (02.03.06 17:56) [12]

> и что либо быстрее ListView в виртуальном режиме я не встречал


Canvas.Draw.
Но, дело в том, что ListView управляется теми же SendMessage,
так что в этом компоненте он ничем не лучше даже synchronize.
А то, что управлять его перисовкой сложней, чем, скажем ListBox,
тоже кажется очевидным.

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2006-03-02 18:15) [15]


> MegaVolt ©   (02.03.06 17:56) [12]

> >А вот SendMessage
> Можно чуть поподробней или примерчик. Я с этим не очень
> сталкивался. Ведь поток тоже будет ждать пока будет обработан
> SendMessage. В чём выигрышь.


 SendMessage(StaticText1.Handle, WM_SETTEXT, 0, LParam(PChar(s));

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

Да, и ждать здесь вовсе не зазорно.
Бо, поспешишь - поток насмешишь.

--
Regards, LVT.


 
MegaVolt ©   (2006-03-02 18:52) [16]

>Если он используется аналогично, то вопрос об его нужности еще более значим.

Он применяется для того чтобы запускаемые потоки могли в нём регистрироватся. Т.е. при создании управляющий поток прописывает данные в TThreadList а по завершению поток себя от туда стирает.

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

Такой подход правилен?

>Но, дело в том, что ListView управляется теми же SendMessage,
так что в этом компоненте он ничем не лучше даже synchronize.

Извини не понял :( Кто в каком компоненте чем управляется?
Само собой рисовать на канве можно и самому и это быстрее всего но уж очень лениво организовывать самостоятельно отрисовку сетки, заколовков, обработку нажатия на строчках и пр... Да и собственно ListView осуществляет перерисовку раз в секунду и количество элементов не больше 255 так что скорость его отрисовки меня собственно вообще не интересует.

StaticText1 это что за элемент? Или это просто на форме обработчик моего сообщения? Т.е. я бы не хотел напрямую из потоков командовать отрисовкой. Пусть сохранится где то а потом уж если нужно отобразится.


 
Leonid Troyanovsky ©   (2006-03-02 19:09) [17]


> MegaVolt ©   (02.03.06 18:52) [16]


> В TThreadList хранится время старта потока, и указатель
> на сам поток чтобы его можно было при необходимости остановить.

Эту информацию первичный поток может хранить и использовать
вполне безопасно в любом списке: время старта записывается
в конструкторе, а останавливается потоки путем Terminate.

> Извини не понял :( Кто в каком компоненте чем управляется?

ListView управляется сообщениями, путем SendMessage.
 
>  Да и собственно ListView осуществляет перерисовку раз в
> секунду и количество элементов не больше 255 так что скорость

Т.е., он обновляется по таймеру? Так бы сразу и сказал.

> StaticText1 это что за элемент? Или это просто на форме

TStaticText.

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2006-03-02 19:21) [18]


> MegaVolt ©   (02.03.06 18:52) [16]

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


Тогда вместо ThreadList лучше сделать каждому потоку
поле, содержащее нужную информацию.
Доступ к нему (Get/Set) защищается отдельной критической
секцией (TCriticalSection) - также полем потока.
Тогда вторичные потоки друг-другу мешать не будут,
а доступ к нужному свойству из первичного осуществляется
как чтение свойства (или функцией Get).

--
Regards, LVT.


 
MegaVolt ©   (2006-03-03 10:57) [19]

>Эту информацию первичный поток может хранить и использовать вполне безопасно в любом списке: время старта записывается в конструкторе, а останавливается потоки путем Terminate.

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

>Доступ к нему (Get/Set) защищается отдельной критической секцией...

Так ThreadList так же и работает или я не прав?

Давайте я опишу что должно быть как это сделано сейчас а вы посоветуете как это изменить...

Вот что я хочу получить:
Главный поток запускает управляющий поток.
Управляющий поток запускает некоторое фиксированное количество рабочих потоков и собирает информацию по результатам работы рабочих потоков.
В главном потоке пользователю нужно выводить статистику из второго потока о собранной информации. А так же время работы и состояние каждого рабочего потока. Так же из главного потока нужно завершать работу всех потоков.

Как это сделано сейчас:
1. Запускается управляющий поток.
2. В управляющем потоке запускается цикл от 0 до N, где N гораздо больше разрешенного количества потоков. В цикле стоит WaitForSingleObject для семафора.
3. При запуске рабочего потока инкрементируем семафор, сохраняем в ThreadList указатель на поток и время его работы.
4. В рабочем потоке при изменении статуса изменяем переменную в ThreadList
5. По завершению работы рабочего потока декрементируем семафор, удаляем запись из ThreadList, выводим статистику на форму через Synchronize.
6. В основном потоке по таймеру вычитываем из ThreadList информацию о состоянии потоков и времени их работы.

Как я понял пункт 4 нужно заменить на SendMessage? Только я не совсем понял кто будет принимать сообщение если я не хочу его напрямую передавать на форму. Т.е. передавать TStaticText я бы не хотел.

Что ещё нужно исправить?


 
Гаврила ©   (2006-03-03 11:47) [20]


> Leonid Troyanovsky ©   (02.03.06 17:39) [11] [Новое
>сообщение][Ответить]
>
>> Гаврила ©   (02.03.06 17:31) [9]
>
> > Я аналогичную задачу выполняю так - отправляю
>пост-мессаджи
>
>
>PostMessage строки (string) опасно.
> А вот SendMessage - вполне, скажем, to StaticText.


Строку так передавать нельзя. Зато так можно передавать Pchar (с освбобождением памяти на приемнике)
A SendMessage тут как раз и не подходит (по причине как раз многопоточности)


 
MegaVolt ©   (2006-03-03 12:53) [21]

Так Send или Post или вообще ничто нельзя?


 
Гаврила ©   (2006-03-03 13:04) [22]


> MegaVolt ©  


Send - это то же самое как будто вызвал метод напрямую. То есть синхронизация отсутствует.
Post - ставит сообщение в очередь и возвращает управление немедленно (когда оно там обработается оконной процедурой - зависит от окна). То есть это потокобезопасно


 
Leonid Troyanovsky ©   (2006-03-03 13:09) [23]


> MegaVolt ©   (03.03.06 10:57) [19]


> Так поток который запускает рабочие потоки это не главный
> поток. Т.е. запуском рабочих потоков управляет отдельный

IMHO, первичный поток вполне справится с диспетчеризацией.

> Так ThreadList так же и работает или я не прав?

ThreadList защищает свой список одной секцией, т.е.,
когда потоков много они могут мешать друг-другу.

> Как я понял пункт 4 нужно заменить на SendMessage? Только

Вообще-то, непонятно назначение семафора.
А в остальном, в [18] я предлагал, как реализовать.
Т.е., первичный поток (по таймеру) опрашивает состояние
вторичных потоков. Причем, запрашиваемое свойство
может быть любым (не только String).

> Что ещё нужно исправить?

IMHO, многопоточные приложения должны быть устроены
настолько просто, насколько это, вообще, возможно.

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2006-03-03 13:15) [24]


> Гаврила ©   (03.03.06 13:04) [22]

> Send - это то же самое как будто вызвал метод напрямую.
> То есть синхронизация отсутствует.


Нет, конечно.
SendMessage вызванный из другого потока ставится в очередь
синхронных сообщений, а при его обработке оконная процедура
выполняется в контексте потока, владеющего окном,
т.е., в нашем случае - первичным потоком.
Отправивший же сообщение поток дожидается результата.

Т.е., налицо все, что требуется от синхронизации.
Кстати, в ранних версиях дельфи она так и реализовывалась.

--
Regards, LVT.


 
MegaVolt ©   (2006-03-03 13:26) [25]

>IMHO, первичный поток вполне справится с диспетчеризацией.

А каков тогда должен быть алгоритм его работы чтобы пользователь этого не заметил. В цикле проверять число запущенных потоков? А как быть с обработкой пользовательского ввода. Да и результаты собраные потоками достаточно объёмны и их сохранение в файл из основного потока мне кажется займёт время.

>Вообще-то, непонятно назначение семафора.

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

Если это не правильно то как тогда ограничивать количество запущенных потоков некоторым числом?


 
Leonid Troyanovsky ©   (2006-03-03 13:43) [26]


> MegaVolt ©   (03.03.06 13:26) [25]


> А каков тогда должен быть алгоритм его работы чтобы пользователь
> этого не заметил. В цикле проверять число запущенных потоков?

Зачем в цикле? Запустил поток - inc, закончился поток - dec.
Т.е., если значение больше допустимого - не запускаем.

>  А как быть с обработкой пользовательского ввода. Да и результаты
> собраные потоками достаточно объёмны и их сохранение в файл
> из основного потока мне кажется займёт время.

А чего там за результаты? Случайные числа ? :)
Кстати, каждый поток может писать в свой файл, делов-то.

Насчет семафора: так тоже делают, смутило большее N.

--
Regards, LVT.


 
Игорь Шевченко ©   (2006-03-03 14:02) [27]

MegaVolt ©   (03.03.06 13:26) [25]

посмотри на

http://www.schevchenko.net.ru Supermarket


 
MegaVolt ©   (2006-03-03 14:38) [28]

>А чего там за результаты? Случайные числа ? :)

Результат сканирования компутера

>Кстати, каждый поток может писать в свой файл, делов-то.

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

>посмотри на Supermarket

Посмотрел. К нему бы хоть малюсенький ReadMe.
А так первое что бросилось в глаза UM_ENDSIMULATION главной форме посылается а вот в форме обработчика этого события нету. Или я что то непонял?


 
Игорь Шевченко ©   (2006-03-03 14:57) [29]


> К нему бы хоть малюсенький ReadMe.


Это к Рихтеру - он автор оригинального примера. "Windows для профессионалов", 3-е издание.


> А так первое что бросилось в глаза UM_ENDSIMULATION главной
> форме посылается а вот в форме обработчика этого события
> нету


Это здесь рыбу заворачивали. В смысле, конфликт версий.


 
Leonid Troyanovsky ©   (2006-03-03 15:58) [30]


> MegaVolt ©   (03.03.06 14:38) [28]

> Так проблема не в том куда писать а в том что запись занимает
> время. Т.е. мой главный поток вместо работы с пользователем
> будет заниматся сохранением результатов и это явно будет


Ну, во-первых, почему главный, когда сохранять будет каждый.
Во-вторых, чудес не бывает - больше потоков, меньше процессорного
времени достанется каждому (при равных приоритетах).

Т.е., все равно нужен компромисс между степенью интерактивности и
объемом данных сканирования (кстати, непонятно, почему этот
процесс нуждается в присутствии пользователя).

--
Regards, LVT.


 
MegaVolt ©   (2006-03-03 16:10) [31]

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

Понял. Это не совсем подходит мне нужен один результируюющий файлик. И потом отдельно собирать его из кучи маленьких неохота.

>Во-вторых, чудес не бывает...

Знаю. Один лишний поток погоды не сделает.

>кстати, непонятно, почему этот процесс нуждается в присутствии пользователя

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


 
Leonid Troyanovsky ©   (2006-03-03 16:27) [32]


> MegaVolt ©   (03.03.06 16:10) [31]

> файлик. И потом отдельно собирать его из кучи маленьких
> неохота.


Маленькие - это какие? И куча - это сколько?
Вполне возможно, что всю запись в файл можно сделать
в первичном потоке совершенно ненапряжно для пользователя.
Например, в обработчике WM_COPYDATA формы.

--
Regards, LVT.


 
MegaVolt ©   (2006-03-03 16:40) [33]

>Маленькие - это какие? И куча - это сколько?

Файликов будет штук 200-300. Суммарный объём под 100Мег
Т.е. например у меня на машине запись 100Мег это 4 секунды. Значит пользовательское приложение за время работы будет будет в сумме недоступно 4 секунды. Впринципе немного но заметно должно быть.

Собирать в кучу неохота потому что для этого понадобится ещё столько же места на венике. Некрасиво однако.


 
Leonid Troyanovsky ©   (2006-03-03 16:56) [34]


> MegaVolt ©   (03.03.06 16:40) [33]

> Файликов будет штук 200-300. Суммарный объём под 100Мег
> Т.е. например у меня на машине запись 100Мег это 4 секунды.
>  Значит пользовательское приложение за время работы будет
> будет в сумме недоступно 4 секунды. Впринципе немного но
> заметно должно быть.


Т.е., ты не знаешь чем развлечь юзера в течении 4 сек?
Попроси его следить за красной (желтой) лампочкой на корпусе.

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

--
Regards, LVT.


 
MegaVolt ©   (2006-03-03 17:24) [35]

>Т.е., ты не знаешь чем развлечь юзера в течении 4 сек?

Весь процесс занимает минут 20 за это время будет собрано 200-300 кусков информации которые в сумме дадут 100Метров. Если запрячь эти 100Метров писать главный поток то форма будет недоступна пользователю в общей сумме 4 сек. Т.е. пользователь может наблюдать рывки например при перетаскивании или замедленную реакцию на нажатие каких либо контролов или ещё что либо... Мне кажется это некрасиво.


 
Leonid Troyanovsky ©   (2006-03-03 18:28) [36]


> MegaVolt ©   (03.03.06 17:24) [35]

> или ещё что либо... Мне кажется это некрасиво.


Мне вообще непонятно, что там такого ценного в компьютере
стоит 100Мб информации (статистика излюбленных сочетаний символов
в файлах юзера?). И, зачем ему, собс-но, пялиться целых 20 мин
на все это, убиваясь из-за каких-то 4 сек  (задержка 4/(20*60),
если человеческий глаз воспринимает 1/24 сек).

--
Regards, LVT.


 
MegaVolt ©   (2006-03-06 10:22) [37]

>что там такого ценного в компьютере стоит 100Мб информации

Список файлов доступных на доступ с их атрибутами.

А задержку ты считаешь не совсем верно. Т.к. сохранение ты предлогаешь делать в одном потоке то есть шанс что все запущенные потоки станут в очередь на сохранение результатов. Т.е. допустим 10 потоков хотя бы по 1 Метру (а если предположить наихудший случай то и 2-5метров), уже получаем 10 метров а раз или 0,5 сек. Само собой юзер перетерпит эту задержку никуда не денется тем более на фоне тормозов софта от мелкософта вообще не много но что то мне очень не охота становится похожим на мелкософт :)


 
Leonid Troyanovsky ©   (2006-03-06 11:14) [38]


> MegaVolt ©   (06.03.06 10:22) [37]

> Список файлов доступных на доступ с их атрибутами.


И просматривать 100Мб в блокноте. Ню-ню.

> А задержку ты считаешь не совсем верно.

Ну, это лишь для девушек имеет большое значения.
Кста, исходные данные - твои. Про равномерность записи указаний не было.
Да и, пусть даже неравномерно - диск-то 1?

Юзер 4 сек переживет спокойно, если, конечно, не записывать
чрезмерного размера буферы (размера кластера вполне достаточно).
И нет тут особой разницы, сколько потоков пишут.

--
Regards, LVT.


 
Crash Coredump ©   (2006-03-06 14:42) [39]

А вот Google Desktop работает быстро и незаметно. Занимается куда как большей работой, чем составление списка файлов с атрибутами доступа.


 
GrayFace ©   (2006-03-06 14:57) [40]

Leonid Troyanovsky ©   (03.03.06 13:15) [24]
Т.е., налицо все, что требуется от синхронизации.
Кстати, в ранних версиях дельфи она так и реализовывалась.

Не только в ранних. В Delphi 7 это тоже так.

MegaVolt
Обновлять статистику, по-моему, лучше всего методом [9]+[22]. В [22] написана ерунда про SendMessage, но алгоритм с Post описан верно и должен дать наилучший результат.

Leonid Troyanovsky ©   (03.03.06 13:43) [26]
Зачем в цикле? Запустил поток - inc, закончился поток - dec.
Т.е., если значение больше допустимого - не запускаем.

Точнее, запуск - InterlockedIncrement, завершение - InterlockedDecrement и PostMessage гл. потоку. Главный поток вначале запускает потоков до предела, потом запукает потоки при получении сообщений.

Запись в файл - точно так же - PostMessage и запись в главном или записывающем потоке. Но не WM_COPYDATA, а свое сообщение с указателем и размером в параметрах. Записывающий поток после записи будет освобождать память.



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

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

Наверх





Память: 0.59 MB
Время: 0.015 c
2-1143133012
Kolan
2006-03-23 19:56
2006.04.09
Что значит public var?


2-1143105289
Der Nechk@ssoff
2006-03-23 12:14
2006.04.09
Сканирование папки


4-1137944963
Dyakon_Frost
2006-01-22 18:49
2006.04.09
Отключение системных служб


15-1142688836
TStas
2006-03-18 16:33
2006.04.09
РЕальная необходимость рекурсии


3-1139663245
Chel
2006-02-11 16:07
2006.04.09
Работа с TDBGrid





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