|
|
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Вопрос по использованию коннекта к базе в отдельном потоке. Хотел бы узнать кто как это делает. Например, если я внутри класса TThread объявляю DataModul с компонентами IBX. При создании потока, создаю дата модуль, подключаюсь к базе (CB6\IBX, FB1.5). Когда хочу получить данные, то из основного потока заполняю DataSet.SQL и назначаю для DBGrid, который расположен в "основном VCL" потоке DataSet из вторичного потока, после чего активирую EVent, которого ждет "тело" потока. В потоке происходит запрос и на DBGride вижу данные, пока внутри тела потока не сделаю Commit || Rollback. Запрос не модифицирующий (только просмотр). Вроде все работает, но все же у меня вопрос - можно ли так делать? Ведь получается, что напрямую взаимодействуют компоненты, "живущие" в разных потоках. И как быть, если надо будет не только смотреть но и редактировать? В общем, хотелось бы, ссылки на статью или "хороший" исходник с помощью которого я бы прояснил для себя полностью ситуацию с тем, как грамотно организовать клиента, в котором обмен с сервером идет в потоке (потоках) параллельному основному. Заранее спасибо всем кто откликнется... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.12.2003, 13:09 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Посмотри на ibase.ru - там есть статья с примером на эту тему. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.12.2003, 13:22 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Видел я и статью и исходник. Там делается так: в основном потоке находится StringGrid, указатель на который передается в поток и строки грида заполняются с помощью Synchronize, но это не совсем то. С таким же успехом можно передать массив строк и переменных, которые я потом вставлю в Edit-ы и Box-ы. Только нафига такое надо? Зачем тогда нужны все эти визуальные компоненты по работе с данными? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.12.2003, 14:20 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
по моему, будут проблемы, так как gds32 не поддерживает многопоточный доступ. Но лучше всего проверить это дело на хорошем тесте и нам тут сообщить, что да как - очень интересно. With best regards, Alexey Kovyazin ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.12.2003, 14:24 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Мне тоже надо распараллелить кое что, но оно не срочно пока и я никак не собирусь это попробовать. Так что помочь не могу :-/ ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.12.2003, 14:32 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Сейчас у меня сделано так: Основной VCL-поток порождает два дочерних, которые работают один на прием, другой на передачу данных на сервер. В принципе, почти работает.... "Почти" заключается в том, что иной раз возникает проблема со "StartTranzaction". Теперь думаю изменить программу так, чтобы параллельный поток был один, хотя по логике задачи и структуре программы их должно быть два. В общем-то сначала нужно хотя бы один заставить стабильно работать, а дальше погляжу... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.12.2003, 14:46 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Господа, главное, что не многопоточен VCL! Из другого потока нельзя даже ShowMessage сделать. У меня по этому поводу были мысли даже вместо VCL для части задач использовать просто С++ wrapper для gds32. Можно, конечно вызывать через Synchronize, но тогда теряется весь смысл много поточности (интерфейс "подвисает"). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.12.2003, 15:10 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Почему смысл многопоточности пропадает? Например, у меня "длинный" запрос к базе, но в основном потоке должна идти обработка другой информации. А по завершению запроса нужно вернуть одну строку. Тогда Synchronize в самый раз. Потоку данные передал, запустил его и занимайся своими делами. Как транзакция отработала - получи результат "синхронно". Только вот, если гриды нужно в основной форме иметь, тогда да... :( ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.12.2003, 15:21 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Хммм... выполнение запроса из другого потока? BCB HelpWhen you use objects from the VCL object hierarchy, their properties and methods are not guaranteed to be thread-safe. That is, accessing properties or executing methods may perform some actions that use memory which is not protected from the actions of other threads Ой... как бы не нарваться... Правда скорее всего это связано именно с отображаемыми компонентами (обычно подобного рода ошибки проявляются в виде Exc Canvas Doesn't allow drawing), но цитата из хелпа удерживает меня пока от работы с VCL из другого потока. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.12.2003, 16:32 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Отсюда неутешительный вывод: если хочешь работать с потоками, то про визулизацию придется забыть :( или реализовывать её своими способами, передавая данные, например, используя критические секции... вдвойне :(( ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.12.2003, 17:04 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
zahodunили реализовывать её своими способами, передавая данные, например, используя критические секции Дык... В том то и дело, что НЕТ. Даже если внутри твоей проги доступ к Form1->Label1 Синхронизирован (ты точно знаешь, что в каждый момент времени менять ее могит только 1 поток), то все равно ничего не получится, просто Form1->Label1->Text = "blabla" - это уже потоконебезопасно. Т.е. ты НЕ имеешь права включить такую строку в код, исполняемый в твоем потоке ( даже косвенно, например TThread1->RefreshForm(), который вызывает Form1->UpdateLabel1(), в котором есть эта сторока) ). Ота! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.12.2003, 17:15 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Ура! Все не так плохо. BCB HelpData access components are thread-safe as follows: For BDE-enabled datasets, each thread must have its own database session component. The one exception to this is when you are using Access drivers, which are built using a Microsoft library that is not thread-safe. ADO and InterbaseExpress components are thread-safe. Так что век живи век читай help. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.12.2003, 17:21 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Теперь еще нужно опытным путем выяснить насколько оно "safe". А то в хелпе написать можно чего угодно... :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.12.2003, 17:47 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Константин Хлопов прежде чем утверждать о возможности многопоточного VCL... нужно вообще знать в чем траблы и когда возникают.... в твоем примере с label'ом... один поток пишет в буферную переменную а второй поток читает из нее в label... разумеется и чтение и запись закрыты критическими секциями, а выигрыш в многопоточности есть. Ты можешь исполнять запрос скажем минуту в отдельном потоке и в это же время заниматься другими вещами. Если этих "других вещей" нет, то нехрен многопоточник городить. В случае с гридом... есть мысль... только в качестве буферной переменной юзать нечто куда будет выливаться результат запроса. Как недостаток следует признать необходимость полного fetch записей. Alexey Kovyazin по поводу "gds32 не поддерживает многопоточный доступ"... Странно... Во-первых, я это использую, причем тестировал в режиме когда это удовольствие обязано было свалится... Да и потом... dll одна... а приложения запускаем два... уже получилась многопоточность... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.12.2003, 03:40 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Ню-ню... пример текст метода Execute единственного пользовательского потока: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. ~300 нормальных вызовов потом Exception. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.12.2003, 10:57 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
2 Константин Холопов Так нельзя! Нужно: TThread::ShowCaption() { ShowMessage(...Caption); } TThread::Execute { while(..) { .... Synchronise(ShowCaption); } } ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.12.2003, 11:10 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Вот именно! Любые операции с компонентами которые ЯВНО не классифицированы как многопоточные можно производить только из основного потока приложения (что и делает Synchronize). Но Message LOOP тоже работает в основном потоке. Поэтому вызов тяжелой ф-и через Synchronize сводит на нет использование потока. Понятно, что все это шаманством всяким можно обойти... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.12.2003, 11:54 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Вот-вот. Для "тяжелых" функций я и применяю буфер, защищенный критической секцией. Когда то обычный - линейный. Иногда удобно кольцевой. А вот как быть с DB? Фиг его знает. Заталкивать Select в array, потом выковыривать, отображать. После чего заталкивать в буфер Update или Insert и опять в поток? Уж больно навороченно получается. Как правило, если в программе столько наворотов, то и стабильность у нее обратно пропорциональная. А деваться некуда. Мой "клиент" кроме работы с сервером IB еще является и клиентом другого "реал-тайм" сервера. Обмен с которым идет напрямую по IP синхронно. Пакет - ответ. И я не могу себе позволить, чтобы обмен прекратился или задержался даже на секунду, а запрос к базе вполне может длиться и несколько секунд. Вот такие пироги... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.12.2003, 12:23 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
А может общение с сервером выделить в поток? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.12.2003, 12:43 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Те же яйца - вид сбоку :) С сервера приходит состояния реальных объектов, которые нужно отображать, опять же в реальном времени. Кроме того, ими нужно управлять. И если базе всё равно - отдам я ей запись сейчас или несколько позже, то реальным объктам это очень даже критично. Если оператор нажал кнопку, то и реакция должна быть немедленной. Поэтому я решил, что именно это будет в основном потоке, а IB в дополнительном. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.12.2003, 13:30 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Константин Хлопов мда..... это видно комне относилась "реализация" Execute.... По мойму я уже писал... что так нельзя...нужно перекрывать критическими секциями.... а ты снова за свое... Да и я не вижу смысла многозадачности, если тут происходит работа фактически в главном потоке... вот если у тебя было бы вместо тупого инкремента скажем разложение Фурье, то тут был бы выигрыш... zahodun для твоего случая... работает у меня подобная штука и на удивление стабильно и безотказно. Да и время очень жестко задано. В терх потоках живет (погоди всеж в четерех) общение с прогой по телнету, чтение данных с COM-порта каждые 100мс и общение с базой, которое может затянуться и на секунду и даже подольше... При том что результат чтения отображается в окне и в принципе я думаю можно редактирование прикрутить. А ларчик просто открывается. Например в потоке 1 тебе надо чтоб была форма (подчеркиваю это не главный поток в обычном понимании). Тогда ты именно в этом потоке создаешь форму (create) и в нем же даешь команду на отображение (show). Далее, дабы й тебя поток не прекратил свое существование слишком оперативно (то есть сразу после создания формы) оформляешь следующую последовательность команд: Код: plaintext 1. 2. 3. 4. синтаксис дельфей, но думаю переведешь. Sleep обязательно, дабы проток не грузил комп по напрасну. Можно этим спипом рулить приоритет своеобразно весьма. Разумеется, если мы завершаем поток, то необходимо убить форму. Точно так же можно создавать сколь угодно много форм. Причем разумеется в одном потоке. Объмен информацией между потоками я осуществляю через очередь. сразу предупрежу. Та что идет стандартно нельзя использовать, так как не поддерживает многопоточность. Я писал свою, если надо поделюсь, но разумеется написана на дельфе. И в заключении скажу, что вся эта конструкция работает дополнительно и в dll и прекрасно функционирует. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.12.2003, 03:38 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
StarWind Раз у тебя все так здорово работает, то может тогда прояснишь мне несколько моментов насчет многопоточности? :)) Вот ты говоришь, что нужно создавать форму внутри потока. У меня и ДатаМодуль тоже создается внутри потока, но я только сейчас подумал. А внутри ли? Т.е. сейчас сделано так: class TIBThread : public TThread { private ... TReadDM * DM; // DataModul ... } Но создаю я его не внутри Execute, а при создании потока. TIBThread::TIBThread(bool CreateSuspended) { ... DM = new TReadDM; } Разваливаю естественно, тоже в деструкторе Thread`a. Но скорее всего получается, что при таком подходе модули создаются в основном потоке? Может нужно реализовать все создания подключения/отключения/разваливание внутри метода Execute? В общем, что-то я вконец запутался с этими потоками. Да и в литературе этот вопрос что-то слабо освещен. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.12.2003, 09:51 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
датамодуль это просто контейнер и все. У него нет собственной очереди сообщений, поэтому вообще говоря не важно где его создавать. Я говорил все в отношении форм где и происходят все накладки при одновременном доступе из двух потоков. Если ты подменишь датамодуль на форму, то тут уже можно говрить осмыслено и в твоем случае форма окажется "привязана" к главному потоку. Привязана именно очередью. Немного проясню откуда все траблы. Например мы пытаемся модифицировать label во втором потоке. При присваивании значения, оно автоматически отображается на форме и пишется в некую область памяти. В самый неприятный момент в очередь главного потока падает событие WM_PAINT, которое заставляет перерисоваться окно и соответственно и изменить информацию в той же самой области памяти, где и шарится второй поток. В итоге, происходят вещи, предсказать которые, крайне трудно. Что происходит в случае когда окно создано и показано в коде второго потока? Ничего страшного кроме провязывания внутренних переменных библиотеки VCL и WinAPI. Когда же мы принудительно вызываем функцию ProgressMessages происходит обработка событий в очередях тех окон, которые созданы именно в этом потоке, откуда был вызов . В итоге, мы получаем, что работой окна управляет именнонаш вторичный поток и не касается его главный. Для доказательства, можно заблокировать цикл который я приводил, остановив тем самым второй поток. ОКНО ОБНОВЛЯТЬСЯ НЕ БУДЕТ Это я проверял и в принципе и дошел до этих идей именно через подобные тесты. (плюс хелп разумеется) Теперь о твое проблеме. Рисуем в дизайнере нужную нам форму, со всеми элементами редактирования и прочего. Если нужен датамодуль, то можем создавать его где угодно(только разумеется он должен быть создан перед тем как его форма будет юзать, это важно отследить) либо в этой же форме. А потом создаем и показываем форму в функции потока. Все будет работать железно. Потому как это будет фактически однопоточник. Но я бы не советовал юзать компоненты, которые юзаются в форме в другом потоке. Иначе мы напоримся на те же грабли. Обмен можно осуществлять через очередь, но подчеркну еще раз стандартную очередь (компонента TQueue) использовать нельзя. Она не предназначена для обращения к ней из многих потоков, только внутри одного. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.12.2003, 10:38 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
Ну зачем же так мучится? Если у вас есть TClientDataset, то проблема с потоками решается очень просто: Да, в потоке создаете модуль данных, с запросом и провайдером. Подсоединяетесь, выполняете запрос. Потом просто: передаете данные из провайдера в cds в главном потоке, к которой присоединена форма, эти данные - простой OleVariant. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.12.2003, 11:06 |
|
||
|
IBX & TThread
|
|||
|---|---|---|---|
|
#18+
To StarWind Большое спасибо за разъяснение, только непонятно следующее: ... Но я бы не советовал юзать компоненты, которые юзаются в форме в другом потоке. Иначе мы напоримся на те же грабли. Обмен можно осуществлять через очередь, но подчеркну еще раз стандартную очередь (компонента TQueue) использовать нельзя. Она не предназначена для обращения к ней из многих потоков, только внутри одного. ... - 1) не понял, в каком смысле это написано? Что значит юзать компоненты, которые юзаются в другом потоке? - 2) Если нельзя использовать очередь компонента, тогда как? Выдумывать "свою" очередь, защищенную критической секцией? To Roman Ignatiev ... Потом просто: передаете данные из провайдера в cds в главном потоке, к которой присоединена форма, эти данные - простой OleVariant. ... - это как? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.12.2003, 12:21 |
|
||
|
|

start [/forum/topic.php?fid=40&fpage=491&tid=1579437]: |
0ms |
get settings: |
7ms |
get forum list: |
19ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
51ms |
get topic data: |
9ms |
get forum data: |
2ms |
get page messages: |
56ms |
get tp. blocked users: |
1ms |
| others: | 203ms |
| total: | 354ms |

| 0 / 0 |
