Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

VCL и многопоточность...


Страницы:   1 2

Jolik ©   (2004-08-08 00:03:00) 

Здрассте!

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

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

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

Спасибо!


Sha   (2004-08-09 09:40:00) [1]

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


Digitman   (2004-08-09 09:20:00) [2]


> 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;


Chlavik   (2004-08-08 23:56:00) [3]

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


Sha   (2004-08-08 21:30:00) [4]

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

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


Sha   (2004-08-08 21:25:00) [5]

Jolik ©   (08.08.04 21:17) [19]

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


Jolik   (2004-08-08 21:17:00) [6]

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 20:21:00) [7]

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

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

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


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

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


Jolik   (2004-08-08 14:57:00) [9]

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

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). Правда информация проскакивает ТАКИМИ КУСКАМИ :)))

Спасибо!


Sha   (2004-08-08 11:00:00) [10]

> 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;


k-sergey   (2004-08-08 10:53:00) [11]

Ясно.


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

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


k-sergey   (2004-08-08 10:30:00) [13]

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


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

>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.


Fay   (2004-08-08 09:57:00) [15]

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


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

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

В смысле?


Fay   (2004-08-08 08:51:00) [17]

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


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

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

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


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

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

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

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

Резюме.

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


Fay   (2004-08-08 02:15:00) [20]

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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо