Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Организация многопоточного приложения, со связкой форма-поток

19K
25 декабря 2007 года
Termi_uc
33 / / 13.02.2007
Преамбула
Пишу многостраничное приложение для работы с СУБД Oracle.
Каждая страничка - это форма загруженная из bpl файла или созданная динамически из XML-какраса.
К исподникам bpl-формы доступа нету. Исполняемым "кодом" второй является скрипт.
В обоих случаях нету возможности "встроить" многопоточность непосредственно в файл формы.
Компоненты для работы с Oracle потокобезопасные.

Вопрос
[COLOR="Red"]Как лучше всего организовать многопоточность приложения, чтобы для каждой формы загруженной из файла или созданной динамически поставить в соответствие отдельный поток. Поток должен уничтожатся вместе с формой, после вызова Close() последней.[/COLOR]
[Добавлено 09.01.2008 в 03:21]
Вопрос был задан некорректно.
Переформулирую:
Как лучше всего организовать многопоточность приложения, чтобы для каждой формы загруженной из файла или созданной динамически создать отдельный поток, который будет полностью управлять (из которого пользователь будет управлять) этой формой и всеми дочерними [формами].
Предположительно, поток должен будет поддерживать свою очередь сообщений.
Гдавная программа знает только о существовании объекта типа TForm (по-факту, это будет наследник TForm) и экземпляра TThread (потомка). При вызове TThread::Terminate(), должен вызыватся TForm::Close() и наоборот.
И ВСЕ! Больше, никаких инструментов управления/воздействия на модули "главная форма программы"/программа иметь не должна.
Вся логика создания управляющего потока должна быть реализована в потомке TThread.

Конечно, это только примерный алгоритм и Вы можете предложить свои. Для меня только важно, чтобы "главная форма программы"/программа работала с формами как с TForm.

Пример, для чего все это нужно:
В программе p1, доступно 2 модуля m1 и m2. Оба модуля представлены главными формами, которые, при старте, распологаются на вкладках главной формы программы p1 (в общем случае, а в частности может быть и по-другому).
Пусть:
1. В модуле m1 происходят какие-либо долгие процессы. Например создание отчета.
2. Разработчики этого модуля, почему-то поленилесь вынести создание отчета (и/или других процессов) в отдельный поток.
Тогда, для того, чтобы пользователю воспользоватся модулем m2, надо открыть вторую конию (запустить еще раз) программы p1.

Ну, по-моему, уже и так понятно суть, но я все-таки поясню:
Для того чтобы, пользователю не надо было открывать вторую копию программы и необходимо вынести все действия модулей m1 и m2 в отдельные потоки (может быть, со своими очередями сообщений). При этом, мы не знаем что это будут за действия.
По суте, в программе p1 создаются 2 подпрограммы у которых главными окнами будут главные окна модулей m1 и m2.
240
26 декабря 2007 года
aks
2.5K / / 14.07.2006
Ну для начала неплохо бы изучить правила грамотного построения GUI приложения. ФОрма, окно и т.п. - это всего лишь GUI элемент. И его задача - отображать данные, регистрировать реакцию пользователя в GUI. И там не должно быть ни каких созданий потоков, вычислений, алгоритмов и т.п.
Тоесть можно сделать какой либо менеджер окон, который будет создавать окна, связывать их в одном объекте с сущьностью отвечающей за нужную функциональность и выполняющуюся в отдельном потоке. Это объект опячть же и должен следить за своим временем жизни синхронно с окном "формы".
19K
26 декабря 2007 года
Termi_uc
33 / / 13.02.2007
Цитата: aks
Ну для начала неплохо бы изучить правила грамотного построения GUI приложения. ФОрма, окно и т.п. - это всего лишь GUI элемент. И его задача - отображать данные, регистрировать реакцию пользователя в GUI. И там не должно быть ни каких созданий потоков, вычислений, алгоритмов и т.п.



Если ты внимательно прочитаешь мой пост, то не найдешь там ничего противоречащего твоему утверждению.

Цитата: aks
Тоесть можно сделать какой либо менеджер окон, который будет создавать окна, связывать их в одном объекте с сущьностью отвечающей за нужную функциональность и выполняющуюся в отдельном потоке. Это объект опячть же и должен следить за своим временем жизни синхронно с окном "формы".



Если бы ты внимательно прочитал мой первый пост (а я так понял что не внимательно), то ты бы понял, что я спрашиваю именно о том КАК связывать их в одном объекте с сущьностью отвечающей за нужную функциональность и выполняющуюся в отдельном потоке.
Может быть есть какие-либо наработки? Поиск по этому поводу молчит.

1
26 декабря 2007 года
kot_
7.3K / / 20.01.2000
Цитата: Termi_uc
Если ты внимательно прочитаешь мой пост, то не найдешь там ничего противоречащего твоему утверждению.


Если бы ты внимательно прочитал мой первый пост (а я так понял что не внимательно), то ты бы понял, что я спрашиваю именно о том КАК связывать их в одном объекте с сущьностью отвечающей за нужную функциональность и выполняющуюся в отдельном потоке.
Может быть есть какие-либо наработки? Поиск по этому поводу молчит.


Ну так сказали же тебе наработку - создать класс-менеджер, задачей которого будет создание форм, связывание их с потоком, отслеживание состояний пар объектов и очистка памяти по завершению.
Можно эту задачу возлагать на класс приложения - но ИМХО это не самое удачное решение. Можно называть это классом-менеджером, я называю классом-прокси - его задача управление объектами и передача сигналов.
Для более подробного ознакомления - паттерн проектирования "Фабрика классов".

3
27 декабря 2007 года
Green
4.8K / / 20.01.2000
Цитата: Termi_uc

Вопрос
Как лучше всего организовать многопоточность приложения, чтобы для каждой формы загруженной из файла или созданной динамически поставить в соответствие отдельный поток. Поток должен уничтожатся вместе с формой, после вызова Close() последней.


Лучше, чтобы весь GUI работал в одном потоке. Так и проще (не надо будет делать цикл обработки сообщений во всех потоках) и логичнее.
Каждая такая форма является "обозревателем" (см. соотв. паттерн проектирования) и регистрируется для получения соотв. сообщений (сигналов) в некотором менеджере. В менеджере существует потокобезопасная очередь в которую бизнес-логика, выполняющаяся в нескольких потоках, складывает сообщения. В таком варианте создание потоков и форм GUI независимо.
Можно обойтись без общего менеджера, если в нем нет особой необходимости (например, одной форме соответствует один поток), тогда при создании потока ему передается ссылка на обозреватель. Далее этот новый поток "дергает" соотв. методы формы по мере необходимости. В этом случае должен быть некоторый менеджер, который создает сначала форму, потом поток и, возможно, контролирует соответствие их времени жизни.

1
27 декабря 2007 года
kot_
7.3K / / 20.01.2000
Цитата: Green
<skiped>
Можно обойтись без общего менеджера, если в нем нет особой необходимости (например, одной форме соответствует один поток), тогда при создании потока ему передается ссылка на обозреватель.<skiped>


Добавлю. Без общего менеджера стоит реализовывать если формы создаются модально (и разрушаются по месту создания) и отображают данные относительно независимые, в противном случае - лучше потратить время и реализовать нормально класс-менеджер, но это ИМХО. По крайней мере в своих задачах, я исхожу именно из этого.

19K
28 декабря 2007 года
Termi_uc
33 / / 13.02.2007
Неправильный ответ возникает исключительно при содействии неправильного вопроса.
Вам не кажется, что это именно этот случай?

Уважаемые Green и kot_, спасибо Вам за ответы. Но Вы просто ходите вокруг-да-около, извините за ассоциацию.
Я по-моему, вполне точно описал задачу, но может быть не очень... ?

Цитата: kot_

...Без общего менеджера стоит реализовывать если формы создаются модально...


Формы создаются не модально, а наподобии страниц в Opera.

Цитата: Green
Лучше, чтобы весь GUI работал в одном потоке. Так и проще (не надо будет делать цикл обработки сообщений во всех потоках) и логичнее.


Я все-таки, думаю, что обработку сообщений должна взять на себя форма, а поток только посылать их [сообщения] ей.

Цитата: Green
Каждая такая форма является "обозревателем" (см. соотв. паттерн проектирования) и регистрируется для получения соотв. сообщений (сигналов) в некотором менеджере. В менеджере существует потокобезопасная очередь в которую бизнес-логика, выполняющаяся в нескольких потоках, складывает сообщения. В таком варианте создание потоков и форм GUI независимо.


Мне во-первых, не нужна независимость создания потоков и форм. Во-вторых, такой вариант мне кажется слишком сложным и надуманным. В том смысле, что VCL должен поддерживать и более лёгкий путь.

Цитата: Green

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


Вот именно то, что нужно <(например, одной форме соответствует один поток)> - именно так и ставилась задача.
Только я не пойму - зачем поток будет дергать какие-то методы, когда форма должна сама фыполнять свою бизнес-логику, а поток выступает только в качестве некоего "контейнера", благодаря которому форме доставляются сообщения от Windows если эта форма не выполняет сейчас никакого длительного процесса.
Время жизни потока и формы контролирует главный поток [приложения] или главная форма.


Рассуждать про патенты и как это можно сделать теоретически это конечно хорошо и даже очень поучительно, но хотелось бы увидеть реальный кусок кода, который сопоставил бы некое Win32 окно, например через Handle с instance некоего процесса.
Например:

 
Код:
TForm * newForm = new TForm1(this);
AssiciateWindowToThread(newForm->Handle, new Thread);
3
28 декабря 2007 года
Green
4.8K / / 20.01.2000
Цитата: Termi_uc
Неправильный ответ возникает исключительно при содействии неправильного вопроса.
Вам не кажется, что это именно этот случай?
Уважаемые Green и kot_, спасибо Вам за ответы. Но Вы просто ходите вокруг-да-около, извините за ассоциацию.
Я по-моему, вполне точно описал задачу, но может быть не очень... ?


Нет, не кажется. IMHO это тот случай, когда конкретный ответ просто не может быть воспринят не знаю уж в силу чего. Ответы тоже были весьма конкретными.

Цитата: Termi_uc

Я все-таки, думаю, что обработку сообщений должна взять на себя форма, а поток только посылать их [сообщения] ей.


Что ты подразумеваешь под сообщениями? Windows Message? Конечно, оконные сообщения должно обрабатывать окно. :)

Цитата: Termi_uc

Формы создаются не модально, а наподобии страниц в Opera.

Мне во-первых, не нужна независимость создания потоков и форм. Во-вторых, такой вариант мне кажется слишком сложным и надуманным. В том смысле, что VCL должен поддерживать и более лёгкий путь.


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

При чем тут VCL, вообще, не понятно.

Цитата: Termi_uc

Вот именно то, что нужно <(например, одной форме соответствует один поток)> - именно так и ставилась задача.
Только я не пойму - зачем поток будет дергать какие-то методы, когда форма должна сама фыполнять свою бизнес-логику,


Потому, что окно(форма) это лишь способ представления данных. У тебя же вычислительными задачами занимается компьютер, а не монитор.
Разделять бизнес-логику и UI - это стандартная архитектура MVC:
http://ru.wikipedia.org/wiki/Model-view-controller

Цитата: Termi_uc

а поток выступает только в качестве некоего "контейнера", благодаря которому форме доставляются сообщения от Windows если эта форма не выполняет сейчас никакого длительного процесса.


Чего=то я совсем тебя не понимаю... форма у тебя сама по себе живет что ли? Вне потока? :)
Что значит "форма не выполняет длительного процесса"? :)

Цитата: Termi_uc

Рассуждать про патенты и как это можно сделать теоретически это конечно хорошо и даже очень поучительно,


Мы не рассуждали про паттерны, а дали тебе конкретные ответы. Паттерны для того и созданы, чтоб формализовать описание решения.

Цитата: Termi_uc

но хотелось бы увидеть реальный кусок кода, который сопоставил бы некое Win32 окно, например через Handle с instance некоего процесса.


Так и надо было задавать вопрос: "напишите мне код", а не "Как лучше всего организовать".

Цитата: Termi_uc

Например:
 
Код:
TForm * newForm = new TForm1(this);
AssiciateWindowToThread(newForm->Handle, new Thread);


Так не получится. Сообщения будут приходить тому потоку, в котором окно(форма) было создано. Я тебе об этом уже говорил в предыдущем посте.

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

19K
29 декабря 2007 года
Termi_uc
33 / / 13.02.2007
Цитата: Green
...
Ещё раз говорю: создавай окна в одном потоке, а бизнес-логику выполняй в других потоках. Отработал поток свои вычисления, стопори его или уничтожай (первое предпочтительнее) до новой необходимости. Все же элементарно.
...


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

Цитата: Green

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


Интересно, как извлечь вычисления из скомпилированной формы, которая извлекается из BPL методом Install() ???


В общем, на основании всей предыдущей дискуссии я думаю надо сделать так:
1. Создать потомка от TThread
2. Научить потомка создавать формы по TMetaClass'у
3. Создавать экземпляр потомка и передавать в качестве параметра в конструктор TMetaClass

Вроде так должно работать...

1
30 декабря 2007 года
kot_
7.3K / / 20.01.2000
Цитата: Termi_uc
Ты не правильно видешь поставленную задачу. Главный поток программы не дожен ничего знать о вторичных потоках (кроме того, что они существуют), а тем более о формах которые абсолютно независымы в смысле бизнес-логики.


Интересно, как извлечь вычисления из скомпилированной формы, которая извлекается из BPL методом Install() ???


Какая разница каким образом форма создается? И что значит - "как извлечь вычисления"? Форма, как сказал Green, это всего лишь способ представления данных для пользователя. Если в классе формы проводятся какие либо вычисления - реализуй методы доступа к их результатам. В чем затруднение - для меня лично непонятно.

Цитата: Termi_uc

В общем, на основании всей предыдущей дискуссии я думаю надо сделать так:
1. Создать потомка от TThread
2. Научить потомка создавать формы по TMetaClass'у
3. Создавать экземпляр потомка и передавать в качестве параметра в конструктор TMetaClass
Вроде так должно работать...


вероятно работать будет. Хотя по поводу создания форм и потоков выше уже говорилось - повторяться не буду. Я бы для работы с потоком не использовал бы TThread - уж слишком он малофункционален и громоздок. Проще создать свой класс и реализовать в нем необходимый функционал. Зачем в потоке создавать форму - тебе виднее. ИМХО, и я согласен с вышесказанным, это ошибка проектирования.

25K
02 января 2008 года
jurabay
7 / / 19.03.2007
Лично я делаю по рабоче-крестьянски:

//при создании формы
void __fastcall TForm1::FormCreate(TObject *Sender)
{
DWORD p1;
hT1 = CreateThread(NULL,0,Thread1,NULL,0,&p1); //запуск потока
}
//при закрытии
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
TerminateThread(hT1); //прибить
}
11
02 января 2008 года
oxotnik333
2.9K / / 03.08.2007
Цитата: jurabay
Лично я делаю по рабоче-крестьянски:

//при создании формы
void __fastcall TForm1::FormCreate(TObject *Sender)
{
DWORD p1;
hT1 = CreateThread(NULL,0,Thread1,NULL,0,&p1); //запуск потока
}
//при закрытии
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
TerminateThread(hT1); //прибить
}



тут другая тема: заранее ничего не известно про создание формы, она берется из dfm файла, все отдано на откуп юзера

3
03 января 2008 года
Green
4.8K / / 20.01.2000
Цитата: jurabay
Лично я делаю по рабоче-крестьянски:

//при создании формы
void __fastcall TForm1::FormCreate(TObject *Sender)
{
DWORD p1;
hT1 = CreateThread(NULL,0,Thread1,NULL,0,&p1); //запуск потока
}
//при закрытии
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
TerminateThread(hT1); //прибить
}


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

25K
03 января 2008 года
jurabay
7 / / 19.03.2007
Вопрос был:
Как лучше всего организовать многопоточность приложения, чтобы для каждой формы загруженной из файла или СОЗДАННОЙ ДИНАМИЧЕСКИ поставить в соответствие отдельный поток. Поток должен уничтожатся вместе с формой, после вызова Close() последней.
Каков вопрос, таков ответ.
25K
03 января 2008 года
jurabay
7 / / 19.03.2007
Да и как это поток ничего не знает о форме? Handle формы знает?
Ну и пусть посылает сообщения компонентам формы.
3
03 января 2008 года
Green
4.8K / / 20.01.2000
Ты последующие сообщения читал или ограничился топиком?
Все это уже предлагалось.
19K
09 января 2008 года
Termi_uc
33 / / 13.02.2007
Извините за долгое отсутствие - в праздники на работу решил забить :)

Цитата: kot_
Какая разница каким образом форма создается? И что значит - "как извлечь вычисления"? Форма, как сказал Green, это всего лишь способ представления данных для пользователя. Если в классе формы проводятся какие либо вычисления - реализуй методы доступа к их результатам. В чем затруднение - для меня лично непонятно.


Так вот, в том-то и дело, что я не знаю, что будет происходить в форме - будь то вычесления или просто показ пользователю слайдов. Да меня это и не касается.
Поэтому и не могу реализовать методы доступа т.к. см. выше .

Цитата:
Ты последующие сообщения читал или ограничился топиком?
Все это уже предлагалось.


Ну Green кажется понял, что я хочу.

Цитата:

В общем, на основании всей предыдущей дискуссии я думаю надо сделать так:
1. Создать потомка от TThread
2. Научить потомка создавать формы по TMetaClass'у
3. Создавать экземпляр потомка и передавать в качестве параметра в конструктор TMetaClass
Вроде так должно работать...


Так, к сожалению, не работает :(

Пример, для чего все это нужно:
В программе p1, доступно 2 модуля m1 и m2. Оба модуля представлены главными формами, которые, при старте, распологаются на вкладках главной формы программы p1 (в общем случае, а в частности может быть и по-другому).
Пусть:
1. В модуле m1 происходят какие-либо долгие процессы. Например создание отчета.
2. Разработчики этого модуля, почему-то поленилесь вынести создание отчета (и/или других процессов) в отдельный поток.
Тогда, для того, чтобы пользователю воспользоватся модулем m2, надо открыть вторую конию (запустить еще раз) программы p1.

Ну, по-моему, уже и так понятно суть, но я все-таки поясню:
Для того чтобы, пользователю не надо было открывать вторую копию программы и необходимо вынести все действия модулей m1 и m2 в отдельные потоки (может быть, со своими очередями сообщений). При этом, мы не знаем что это будут за действия.
По суте, в программе p1 создаются 2 подпрограммы у которых главными окнами будут главные окна модулей m1 и m2.

P.S. Под очередями сообщений, я конечно же имею введу[всегда] очереди сообщений Windows. А то, где-то вверху непонятка вышла...
P.P.S. Я переформулировал/уточнил/разжевал вопрос. См. первый пост.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог