Модераторы: Poseidon, Snowy, bems, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Произвести синхронизацию формы с потоком, из потока через определённое время 
:(
    Опции темы
Albinos_x
Дата 7.1.2006, 22:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Evil Skynet
****


Профиль
Группа: Комодератор
Сообщений: 3288
Регистрация: 28.5.2004
Где: X-6120400 Y-1 4624650

Репутация: 26
Всего: 108



Собственно САБЖ. Внутри основной выполняющейся функции Sleep не подойдёт. Пока единственный надуманный вариант это через таймер с самой формы с которой синхронизирую, т.к. первоначальный вариант - синхронизация при изменении данных в потоке, не катит, в следствии из очень частого(быстрого) изменения этих данных, форма "виснет"(таже таймер на ней перестаёт работать), как будто я поток и не создаю....

Всем заранее СПАСИБО!


--------------------
"Кто владеет информацией, тот владеет миром"    
Уинстон Черчилль
PM MAIL ICQ   Вверх
Albinos_x
Дата 8.1.2006, 02:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Evil Skynet
****


Профиль
Группа: Комодератор
Сообщений: 3288
Регистрация: 28.5.2004
Где: X-6120400 Y-1 4624650

Репутация: 26
Всего: 108



есть ли у кого-нибудь соображения по этому поводу?

Это сообщение отредактировал(а) Albinos_x - 8.1.2006, 02:59


--------------------
"Кто владеет информацией, тот владеет миром"    
Уинстон Черчилль
PM MAIL ICQ   Вверх
Quadr0
Дата 8.1.2006, 04:22 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











...

Это сообщение отредактировал(а) Quadr0 - 15.7.2011, 09:43
  Вверх
Демо
Дата 8.1.2006, 04:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 30
Всего: 50



Цитата(Albinos_x @ 7.1.2006, 23:52 Найти цитируемый пост)

синхронизация при изменении данных в потоке, не катит, в следствии из очень частого(быстрого) изменения этих данных,


Стандартный способ - синхронизация не каждый прохолд цикла, а только через несколько циклов. Например, каждый 10-й, каждый 100-й, 1000-й, и т.д.
Таймер в потоке не нужен. Для этого достаточно во время цикла использовать GetTickCount и сравнивать с предыдущим полученным значением.

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

Это сообщение отредактировал(а) Демо - 8.1.2006, 04:29


--------------------
    
PM MAIL ICQ Skype   Вверх
Albinos_x
Дата 8.1.2006, 04:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Evil Skynet
****


Профиль
Группа: Комодератор
Сообщений: 3288
Регистрация: 28.5.2004
Где: X-6120400 Y-1 4624650

Репутация: 26
Всего: 108



Цитата(Quadr0 @ 8.1.2006, 04:22 Найти цитируемый пост)

Надо сделать задержку между выводом результатов? Я правильно понял?

да, правильно. Только у меня там организовано что-то наподобии прогрессбара на форме в котором я показываю процесс выполнения потока - что он делает, и сколько сделал из общего количества...
Цитата(Quadr0 @ 8.1.2006, 04:22 Найти цитируемый пост)

Почему?

потому что если я запускаю один поток, то ещё более менее, а вот если два то приложение перестаёт отвечать. Диспетчер задач показывает что оно загрузило на 95% проц. При этом прогресс бар на созданной форме "тикает", но что делает поток не показывает и не показывает сколько времени осталось до завершения работы потока (это у меня реализовано с помощью таймера на форме), перерисовка форм практически не происходит... выглядит ужасно.
Вот я писал почему:
Цитата

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

Цитата(Quadr0 @ 8.1.2006, 04:22 Найти цитируемый пост)

В OnTerminate вручную останвливаешь таймер (уже навсегда, процесс ведь завершён) и происходит последнее обновление формы.

это мне не придётся делать, т.к. после отработки потока форма, которую я создаю динамически уничтожается...
Цитата(Демо @ 8.1.2006, 04:28 Найти цитируемый пост)

Стандартный способ - синхронизация не каждый прохолд цикла, а только через несколько циклов. Например, каждый 10-й, каждый 100-й, 1000-й, и т.д.

это не подойдёт, т.к. я заранее не знаю количество итераций в цикле...
Цитата(Демо @ 8.1.2006, 04:28 Найти цитируемый пост)

GetTickCount и сравнивать с предыдущим полученным значением.

можно поподнобней, что это за зверь? плз...
Цитата(Демо @ 8.1.2006, 04:28 Найти цитируемый пост)

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

и здесь если можно поподробней.... я то пошлю ему сообщение, а как оно будет обрабатываться? задаю такой вопрос, т.к. если бы я послал сообщение форме, через которую обрабатывал бы так информацию, то оно бы это сообщение обработало после того как отработала основная функция...т.е. приложение бы подвисало этак от 1 до 20 минут...и после этого только бы ловило сообщение...

или мне всё таки остановиться на синхронизации из таймера на форме?


--------------------
"Кто владеет информацией, тот владеет миром"    
Уинстон Черчилль
PM MAIL ICQ   Вверх
Демо
Дата 8.1.2006, 05:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 30
Всего: 50



Albinos_x

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

Примеры могу привести, но не зная, как организован поток, это может быть пустая работа ;)
Добавлено @ 05:03
Я так понимаю, что у тебя в цикле идет расчет неких параметров, которые надо динамически отображать на основной форме?
Добавлено @ 05:04
Сейчас приведу пример с GetTickCount.


--------------------
    
PM MAIL ICQ Skype   Вверх
Albinos_x
Дата 8.1.2006, 05:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Evil Skynet
****


Профиль
Группа: Комодератор
Сообщений: 3288
Регистрация: 28.5.2004
Где: X-6120400 Y-1 4624650

Репутация: 26
Всего: 108



Цитата(Демо @ 8.1.2006, 05:01 Найти цитируемый пост)
Ты бы чуть подробнее расписал структуру потока, чтобы от чего-то оттолкнуться.

вот:
Код

type 
  TRecCriptThread = class(TThread)
  private
    status : Integer;
    MaxStatus : Integer;
    StrStatus : string;
    Index :  Integer;
  protected
     procedure ShowResult;
....
     procedure FreeFormRec;
     procedure Execute; override;
   end;

запуск делаю так:
Код

...
len:=Length(MasForm);
SetLength(MasForm,len+1);
MasForm[len].trfFlagRun:=InFlagRun;
...
case InFlagRun of
   1,2 : s:='Запаковка...';
   3   : s:='Распаковка...';
   end;
MasForm[len].trfForm:=TProgressRecCriptForm.Create(Application);
MasForm[len].trfForm.Label2.Caption:=s;
MasForm[len].trfForm.Tag:=len;
MasForm[len].trfForm.Show;
MasForm[len].trfForm.Update;
MasForm[len].trfRecCriptThread:=TRecCriptThread.Create(false);
MasForm[len].trfRecCriptThread.Index:=len;
end;

функция отображения:
Код

procedure TRecCriptThread.ShowResult;
begin
MasFormRec[index].trfForm.Gauge1.MaxValue:=MaxStatus;
MasFormRec[index].trfForm.Gauge1.Progress:=status;
MasFormRec[index].trfForm.Label4.Caption:=StrStatus;
end;

код работы потока нет смысла писать, тогда проще весь юнит сюда прикрепить...
PS: работа с файлами...
Добавлено @ 05:17
да на форме есть ещё таймер который расчитывает оставшееся время:
Код

procedure TProgressRecCriptForm.Timer1Timer(Sender: TObject);
var beg:TDateTime;
    st,mst:integer;
begin
st:=Gauge1.Progress;
mst:=Gauge1.MaxValue;
if Timer1.Tag<>st then
   begin
   beg:=EncodeTime(0,0,1,0)*((mst-st) div (st-Timer1.Tag));
   Label5.Caption:=TimeToStr(beg);
   end
   else
   if mst<=st then
      Label5.Caption:='Завершено....'
      else
      Label5.Caption:='Не определено....';
Timer1.Tag:=st;
end;



--------------------
"Кто владеет информацией, тот владеет миром"    
Уинстон Черчилль
PM MAIL ICQ   Вверх
Демо
Дата 8.1.2006, 05:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 30
Всего: 50



Вот простой пример:

Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

const
    WM_DISPLAY=WM_USER+1;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    procedure OnWMDISPLAY(var msg: TMessage); message WM_DISPLAY;

  end;

    TSimpleThread=class(TThread)
    private
        FValue: Int64;
        FHandle: THandle;
        Finterval: Cardinal;
        procedure Display;
    protected
        procedure Execute; override;
    public
        constructor Create(aHandle: THandle; Interval: Cardinal);
    end;

var
  Form1: TForm1;
  Thr: TSimpleThread;

implementation

{$R *.dfm}

{ TSimpleThread }

constructor TSimpleThread.Create(aHandle: THandle; Interval: Cardinal);
begin
    inherited Create(True);
    FreeOnTerminate := True;
    FHandle := aHandle;
    Finterval := Interval;
    FValue := 0;
    Resume;
end;

procedure TSimpleThread.Display;
var
    L,H: Cardinal;
begin
    L := FValue and $FFFFFFFF;
    H := (FValue shr 32);
    PostMessage(FHandle,WM_DISPLAY,L,H);
end;

procedure TSimpleThread.Execute;
var
    LastTick,CurrTick: Int64;
begin
    LastTick := GetTickCount;
    while not Terminated do
    begin
        FValue := FValue+1;
        CurrTick := GetTickCount;
        if (CurrTick-LastTick>FInterval) or (CurrTick<LastTick) then
        begin
            Synchronize(Display);
            LastTick := CurrTick;
        end;
    end;
end;

{ TForm1 }

procedure TForm1.OnWMDISPLAY(var msg: TMessage);
var
    Value: Int64;
    L,H: Cardinal;
begin
    L := Msg.wParam;
    H := Msg.lParam;
    Value := (H shl 32) + L;
    Label1.Caption := IntToStr(Value);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Thr := TSimpleThread.Create(Form1.Handle,500); //Обновление раз в полcекунды
end;

end.


Добавлено @ 05:45
Для обновления по запросу "извне" возможны несколько вариантов.

1. Используя очередь сообщений
- Создаем очередь для выборки сообщений(например, вызвав в Execute PeekMessage)
- В цикле в Execute проверяем, есть ли сообщение - опять же PeekMessage с флагом PM_REMOVE), если есть - обновляем форму.
- По таймеру из другого потока(например, основного) посылаем сообщение в доп. поток, используя PostThreadMessage
2. Используя объекты синхронизации, например Events, Semaphore
- В основном потоке создается объект синхронизации, устанваливается в NonSignaled
- В доп. потоке в цикле вызываем функция WaitForSingleObject(<Объект синхронизации>,0) для проверки, требуется ли обновлять форму.
- По таймеру из другого потока(например, основного) выставляем объекту синхронизации статус Signaled

В принципе, можно еще придумать варианты, но думаю, что для твоей задачи вполне подойдет любое из решений.
Добавлено @ 05:47
Кстати, надеюсь, что ShowResult у тебя в методе Synchronize вызывается?


--------------------
    
PM MAIL ICQ Skype   Вверх
Albinos_x
Дата 8.1.2006, 05:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Evil Skynet
****


Профиль
Группа: Комодератор
Сообщений: 3288
Регистрация: 28.5.2004
Где: X-6120400 Y-1 4624650

Репутация: 26
Всего: 108



ясно... значит теперь у меня два варианта...
1. Через таймер
2. и через сообщения...
только это мне тогда нужно будет выносить в отдельную процедуру
Цитата

      CurrTick := GetTickCount;
        if (CurrTick-LastTick>FInterval) or (CurrTick<LastTick) then
        begin
            Synchronize(Display);
            LastTick := CurrTick;
        end;

...
наверно всё таки остановлюсь пока на таймере... минимум переделывания....

ВСЕМ ОГРОМНОЕ СПАСИБО!!!


--------------------
"Кто владеет информацией, тот владеет миром"    
Уинстон Черчилль
PM MAIL ICQ   Вверх
Albinos_x
Дата 8.1.2006, 06:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Evil Skynet
****


Профиль
Группа: Комодератор
Сообщений: 3288
Регистрация: 28.5.2004
Где: X-6120400 Y-1 4624650

Репутация: 26
Всего: 108



Цитата(Демо @ 8.1.2006, 05:37 Найти цитируемый пост)
1. Используя очередь сообщений
- Создаем очередь для выборки сообщений(например, вызвав в Execute PeekMessage)
- В цикле в Execute проверяем, есть ли сообщение - опять же PeekMessage с флагом PM_REMOVE), если есть - обновляем форму.
- По таймеру из другого потока(например, основного) посылаем сообщение в доп. поток, используя PostThreadMessage
2. Используя объекты синхронизации, например Events, Semaphore
- В основном потоке создается объект синхронизации, устанваливается в NonSignaled
- В доп. потоке в цикле вызываем функция WaitForSingleObject(<Объект синхронизации>,0) для проверки, требуется ли обновлять форму.
- По таймеру из другого потока(например, основного) выставляем объекту синхронизации статус Signaled

В принципе, можно еще придумать варианты, но думаю, что для твоей задачи вполне подойдет любое из решений.

Прокатит если я сделаю так к примеру:
Код
procedure TProgressRecCriptForm.Timer1Timer(Sender: TObject);
begin
Synchronize(ShowResult);
end;

Цитата(Демо @ 8.1.2006, 05:37 Найти цитируемый пост)
Кстати, надеюсь, что ShowResult у тебя в методе Synchronize вызывается?

угу...
Добавлено @ 06:26
Цитата(Albinos_x @ 8.1.2006, 06:14 Найти цитируемый пост)

Прокатит если я сделаю так к примеру:

нет у меня не прокатит


--------------------
"Кто владеет информацией, тот владеет миром"    
Уинстон Черчилль
PM MAIL ICQ   Вверх
Albinos_x
Дата 8.1.2006, 15:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Evil Skynet
****


Профиль
Группа: Комодератор
Сообщений: 3288
Регистрация: 28.5.2004
Где: X-6120400 Y-1 4624650

Репутация: 26
Всего: 108



Демо
сделал по твоему совету...вот так:
Код
...
type 
  TRecCriptThread = class(TThread)
  private
    status : Integer;
    Integval  : Integer;
    MaxStatus : Integer;
    StrStatus : string;
    Index :  Integer;
    Tik : Int64;
  protected
...
procedure TRecCriptThread.Synchroniz;
var    
    Curr: Int64;
begin
Curr := GetTickCount;    
if (Curr-Tik>Integval) or (Curr<Tik) then
   begin
   Synchronize(ShowResult);
   Tik := Curr;
   end;
end;
....

вызываю её в циклах, а там где просто нужно обновление
вызываю просто:
Код
...
Synchronize(ShowResult);
...

теперь всё работает как надо...
---
теперь возник другой вопрос... но это уже в другой теме...


--------------------
"Кто владеет информацией, тот владеет миром"    
Уинстон Черчилль
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.3467 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.