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

Вниз

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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.53 MB
Время: 0.038 c
3-1091168902
som
2004-07-30 10:28
2004.08.22
Про SQL запросы


14-1091348367
SergP
2004-08-01 12:19
2004.08.22
Какой формат записи двоичного числа в дельфи?


3-1090724957
MSQl
2004-07-25 07:09
2004.08.22
Как выдернуть из БД все записи с определенной датой и числом


3-1091015329
MORA
2004-07-28 15:48
2004.08.22
подчинённая таблица


14-1091742784
Andy BitOff
2004-08-06 01:53
2004.08.22
Администрирование WinXP





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