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

Вниз

VCL и многопоточность...   Найти похожие ветки 

 
Jolik ©   (2004-08-08 00:03) [0]

Здрассте!

Как народ выкручивается когда надо вызывать визуальные компоненты из неосновного потока программы.
Такая задача:
Из нескольких нитей программы в одну точку приходят текстовые предложения, которые должны выводиться в Мемо. Сейчас я данные из разных нитей сначала группирую в защищенный критическими секциями СтрингЛист, и посылаю, причем через ПостМессаже, сообщение в основное окно. В ответ на это сообщение основное окно добавляет в Мемо данные из СтрингЛиста. Решение подсмотрел в реализации Syncronize Дельфей.

Может есть какой другой способ?

Как то читал, что можно вызвать АПИ функцию которая сообщит когда можно вызывать функции визуальных объектов Виндовс, типа как INT21 в ДОСе. Не знаю, относится ли это к VCL (там ведь и у самих борландов куча кода).

Спасибо!


 
Fay ©   (2004-08-08 00:06) [1]

(Synchronize or SendMessage) and F1


 
Jolik ©   (2004-08-08 00:13) [2]

Посмотрите исходники Synchronize - убожество. Тем более, что все что я выше написал - тоже самое.
SendMessage - выполняет код обработки сообщений окна В ТОМ ЖЕ ПОТОКЕ откуда вызывается и поэтому не прокатывает. Да и как передать например строку в сообщении? Можно передать только ссылку, и пока сообщение не отработается, ссылка должна быть активной - тоже не очень красиво...

В любом случае, спасибо!


 
Fay ©   (2004-08-08 01:08) [3]

2 Jolik ©   (08.08.04 00:13) [2]

>> SendMessage - выполняет код обработки сообщений окна В ТОМ ЖЕ ПОТОКЕ

Это УЖАСНО !!! 8) Проверьте в отладчике.

Сделано нкрасиво - просто показать, что я имел ввиду. Надеюсь, Вы простите мне маленькую лень 8)

unit Unit1;

interface

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

const
 WM_FYVM = WM_USER + 345;
type
 TForm1 = class(TForm)
   Button1 : TButton;
   Memo1 : TMemo;
   Button2 : TButton;
   procedure Button2Click(Sender : TObject);
   procedure Button1Click(Sender : TObject);
 private
   procedure WMFyvm(var M : TMessage); message WM_FYVM;
 end;

var
 Form1 : TForm1;

implementation

{$R *.dfm}

var
 dwEvent : DWORD;

procedure ThreadProc(p : PDWORD); stdcall;
var
 r, h : DWORD;
 procedure DoMsg(s : string);
 begin
   SendMessage(Form1.Handle, WM_FYVM, Integer(PChar(@s[1])), 0);
 end;
begin
 h := p^;
 repeat
   r := WaitForSingleObject(dwEvent, 1000);
   case r of
     WAIT_TIMEOUT : DoMsg(Format("Строка от потока %d", [h]));
     WAIT_ABANDONED :
       begin
         DoMsg("Сдохло событие");
         Break;
       end;
     WAIT_OBJECT_0 :
       begin
         DoMsg(Format("Поток %d прощается с Вами", [h]));
         Break;
       end;
   end;
 until False;
 CloseHandle(h);
end;

procedure TForm1.Button2Click(Sender : TObject);
begin
 PulseEvent(dwEvent);
end;

procedure TForm1.WMFyvm(var M : TMessage);
begin
 Memo1.Lines.Add(PChar(M.WParam));
end;

procedure TForm1.Button1Click(Sender : TObject);
var
 h, id : DWORD;
begin
 h := CreateThread(nil, 0, @ThreadProc, @h, CREATE_SUSPENDED, id);
 ResumeThread(h);
end;

initialization
 dwEvent := CreateEvent(nil, True, False, nil);
finalization
 CloseHandle(dwEvent);

end.


 
Jolik ©   (2004-08-08 02:07) [4]

Может (и скорее всего) я и не прав - в Syncronize применяется SendMessage, но при использовании SendMessage мои приложения практически моментально зависали... Приходилось менять на PostMessage (Со всеми вытекающими - в момент когда обрабатывается сообщение ссылка на строку может уже быть недействительной...) Попробую еще раз..
Спасибо!


 
Fay ©   (2004-08-08 02:15) [5]

Да не за что. 8) Удачи.


 
Мастер ©   (2004-08-08 02:51) [6]

>Jolik
о при использовании SendMessage мои приложения практически моментально зависали...

Вы ведь не привели пример своего кода?

1. При частом использовании SendMessage с визуализацией в основном потоке это естественно. Ведь система только и занимается тем, что выполняет оконную процедуру в Вашей программе.
2. Так же будет и при использовании метода Synchronize(что естественно, ведь метод использует для синхронизации SendMessage.
-----------

Резюме.

При очень частом отображении данных в основном потоке из дополнительного смысл в использовании дополнительного потока теряется.
Т.е. в данном случае нужно менять логику программы, а не пенять на то, что "...Synchronize - убожество..."


 
Бином Ньютоныч   (2004-08-08 08:37) [7]

>при использовании SendMessage мои приложения практически моментально зависали

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


 
Fay ©   (2004-08-08 08:51) [8]

2 Бином Ньютоныч   (08.08.04 08:37) [7]
Очередь сообщений - невдолбенная критическая секция.


 
Бином Ньютоныч   (2004-08-08 09:11) [9]

>Очередь сообщений - невдолбенная критическая секция.

В смысле?


 
Fay ©   (2004-08-08 09:57) [10]

2 Бином Ньютоныч   (08.08.04 09:11) [9]
Посмотрите мой пример. Он, конечно, гуано, но, в целом, понятно.
Я понимаю Ваш вопрос, и знаю, что сравнивать объект ядра с субъектом ядра, по меньшей мере странно, но можно 8).


 
Бином Ньютоныч   (2004-08-08 10:04) [11]

>Fay ©   (08.08.04 09:57) [10]
Вероятно, Вы меня не поняли. Я о том, что причиной зависания(Jolik ©   (08.08.04 02:07) [4]) мог быть примерно такой псевдокод:

in secondary thread:
...
entercriticalsection(MySection);
somework;
sendmessage(...mymessage, ...);
leavecriticalsection(MySection);
...

in main thread:

procedure MyMessageHandler...
begin
entercriticalsection(MySection);
somework;  
leavecriticalsection(MySection);
end;

Deadlock is guaranteed.


 
k-sergey ©   (2004-08-08 10:30) [12]

я немного не по теме, но раз вы уж заговорили о потоках:
создаб динамически кучу Image и подгружаю в них картинки...естественно прога подвисает, если картинок очень много...
хочеться запихать это все в поток...
может подскажите? :-)


 
Бином Ньютоныч   (2004-08-08 10:40) [13]

>k-sergey ©   (08.08.04 10:30) [12]
Создавайте свою ветку. И четко формулируйте, что именно подсказать.


 
k-sergey ©   (2004-08-08 10:53) [14]

Ясно.


 
Sha ©   (2004-08-08 11:00) [15]

> Jolik ©   (08.08.04 02:07) [4]
> Приходилось менять на PostMessage (Со всеми вытекающими - в
> момент когда обрабатывается сообщение ссылка на строку может
> уже быть недействительной...) Попробую еще раз..

Ссылка при PostMessage всегда будет действительной, если делать примерно так:

//в основном потоке
type
 Tfrm=...
 procedure FMUpdate(var msg: TMessage); message FM_Update;
 ...

//не забыть менять Tag и значение визуального объекта (в OnClick и т.п.),
//когда пользователь перемещается по невизуальным объектам

//обработка принятого сообщения об изменении состояния объекта
procedure Tfrm.FMUpdate(var msg: TMessage);
var
 Task: TTask; //тот невизуальный объект, к которому относится сообщение
 s: string;
begin;
 integer(Task):=msg.WParam;
 integer(s):=msg.LParam;
 Task.Products.Add(s); //обновили навизуальный объект
 if integer(Task)=Memo1.Tag then Memo1.Lines.Add(s); //обновили визуальный объект
 end;

//в дополнительных потоках - посылка сообщений об изменении
//состояния невизуальных обектов
procedure PostToForm(Msg: cardinal; obj: pointer; const s: string);
var
 t: string;
begin;
 t:=s; UniqueString(t);
 PostMessage(FormHandle,Msg,integer(obj),integer(t));
 pointer(t):=nil;
 end;


 
Jolik ©   (2004-08-08 14:57) [16]

Спасибо за отклики - тем более странно что выходной (че девченок мало симпатичных на улице :))))

2Sha: Ни разу не пробывал, но боюсь что

PostMessage(FormHandle,Msg,integer(obj),integer(t));
pointer(t):=nil;

не будет работать...
PostMessage асинхронная функция и к моменту ее отработки t уже не будет... Или код функции PostToForm заставляет Delphi инкрементировать счетчик ссылок на t?

2ALL:
Я не обнаружил особой разницы между непосредственным вызовом Memo1.Lines.Add(S) из потока и вызовом Memo1.Lines.Add(S) из обработчика сообщения при отправке SendMessage. Т.е. приложение так же зависало после некоторого времени работы. Т.о. я сделал вывод что SendMessage это просто вызов (фактически) диспетчера сообщений окна. (В Вынь 3.11 так и было...) В итоге пришлось сделать кэш на TStringList куда все кидается, а раз в секунду в обработчике TTimer уже делается Memo1.Lines.AddStrings(StringList1). Правда информация проскакивает ТАКИМИ КУСКАМИ :)))

Спасибо!


 
Мастер ©   (2004-08-08 18:16) [17]

>Jolik ©   (08.08.04 14:57) [16]
Единственное, что тебе нужно добавить в обработчик сообщения, это Application.ProcessMessages.
В этом случае твоя программа не будет "зависать".


 
Sha ©   (2004-08-08 20:21) [18]

> Jolik ©   (08.08.04 14:57) [16]
> PostMessage асинхронная функция и к моменту ее отработки t уже не будет...
> Или код функции PostToForm заставляет Delphi инкрементировать счетчик ссылок на t?

Не совсем так. Для того, чтобы сохранить большую свободу и иметь возможность в некоторых процедурах обращаться к данным в string-строках через указатели (т.е. для гарантии неизменности переданных данных) в PostToForm заводится уникальная строка, а в FMUpdate она (по окончании процедуры) уничтожается.

В принципе в приведенном коде вызов UniqueString(t) не обязателен. Можно ее и не вызывать, тогда для не RO-строки PostToForm будет икрементировать счетчик ссылок, а в FMUpdate декрементировать. Однако тогда хакерские штучки при работе с переданной строкой будут противопоказаны.


 
Jolik ©   (2004-08-08 21:17) [19]

2Sha:
Получается в

//в дополнительных потоках - посылка сообщений об изменении
//состояния невизуальных обектов
procedure PostToForm(Msg: cardinal; obj: pointer; const s: string);
var
t: string;
begin;
t:=s; UniqueString(t);
PostMessage(FormHandle,Msg,integer(obj),integer(t));
pointer(t):=nil;
end;

ошибка (описка) pointer(t):=nil; надо делать в FMUpdate?


 
Sha ©   (2004-08-08 21:25) [20]

Jolik ©   (08.08.04 21:17) [19]

Все написано верно. Нет никаких описок :)


 
Sha ©   (2004-08-08 21:30) [21]

Присваивание pointer(t):=nil; требуется как раз для того, чтобы Delphi не освобождала локальную строку по завершении процедуры.

И, наоборот, в FMUpdate мы не отводим память для локальной строки, но позволяем Delphi освободить ее в финале процедуры.


 
Chlavik ©   (2004-08-08 23:56) [22]

Я просто делал класс тоже типа TMessagehandler в котором AllocateWND(HandleMessage) ...  HandleMessage abstract в наследниках этого класса перекрываеш HandleMessage и в Case Massege.Msg of пишеш реакцию на твои месаги (а их я думаю не так уже и много будет, там MM_SetText, MM_SetCaption и так далее) и пишеш насленик от TThread в котором бдет в protected DoMessage которая будет через SendMessageTimeOut слать на NotifyHandle (он же и будет TMessagehandler.handle) слать месаги и всё афигенно пашет....


 
Digitman ©   (2004-08-09 09:20) [23]


> Jolik


одно из изящных решений - передача ссылки на интерфейс IUnknown

IMyData = interface
 function Get_Data: String;
 procedure Set_Data(const Data: String);
 property Data: String read Get_Data write Set_Data;
end;

TMyData = class(TInterfacedObject, IMyData)
private
 FData: String;
protected
 function Get_Data: String;
 procedure Set_Data(const Data: String);
end;

function TMyData.Get_Data: String;
begin
 Result := FData;
end;

procedure TMyData.Set_Data(const Data: String);
begin
 FData := Data;
end;

..

var
 MyData: IMyData;
..
 MyData := TMyData.Create;
 try
  MyData._AddRef;
  MyData.Data := "XXXX";
  PostMessage(hWnd, WM_XXX, Integer(Pointer(MyData)), 0);
 finally
  MyData := nil;
 end;

...

procedure TMyObject.WMXXX(var Message: TMessage);
var
 MyData: IMyData;
begin
 MyData := IMyData(Pointer(Message.wParam));
 Memo.Lines.Add(MyData.Data);
 MyData := nil;
end;


 
Sha ©   (2004-08-09 09:40) [24]

Фактически [23] - это аналог [15].
Оба варианта - пересылают string наиболее естественным образом.
Первый чуть быстрее, второй понятнее.



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

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

Наверх




Память: 0.54 MB
Время: 0.055 c
1-1091708352
Coder: TCoder;
2004-08-05 16:19
2004.08.22
"..." (переменное число параметров)


4-1089200295
Profffff
2004-07-07 15:38
2004.08.22
Трабл с CreateThread ..... Plz, help!


1-1091703204
mouse_web
2004-08-05 14:53
2004.08.22
Split строки


14-1091341736
ИМХО
2004-08-01 10:28
2004.08.22
Программирование мелодий siemens C62


14-1090840675
X9
2004-07-26 15:17
2004.08.22
I can not find KPPP