![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
VCL и многопоточность...
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) Удачи.