![]() |
Модераторы: Poseidon, Snowy, bems, MetalFan |
![]() ![]() ![]() |
|
oleg153 |
|
||||
Новичок Профиль Группа: Участник Сообщений: 34 Регистрация: 1.3.2007 Репутация: нет Всего: нет |
Есть 3 приложения :
- Клиент (1) - Сервер-Клиент (2) - Сервер (3) Основное - (2) . Описаны две процедуры которые работают с MSSQL через ADO. Процедура-2 вызывается Клиентом(1) , Процедура-1 вызывается Сервер-Клиентом (2). Обе процедуры исполняются на Сервер-Клиенте. В процесе исполнения Процедуры-1 , Сервер (2) - обращается к внешнему Серверу(3) . Проблемма в том что НИКАК ни через Критич. Секции, Ни через Мьютексы не могу заставить процедуру-2, ждать пока не отработается процедура-1. Как только я вызываю метод реализованый на Сервере (3) вся защита слетает и начинает отрабатываться процедура-1 запущеная Клиентом.
В общем как доходит Процедура-1 до DServ.Test1(7000); Вся защита срывается и начинает отрабатываться procedure TForm1.SetData2 которая в этот момент ждет исполнения вызваная Клиентом (1).
Мне НУЖНО чтоб Процедура-1 отработалась до конца и только потом запустилась ждущая Процедура-2 Подскажите КАК это сделать. Бьюсь уже вторые сутки.... |
||||
|
|||||
MetalFan |
|
|||
![]() Аццкий Сотона ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3815 Регистрация: 2.10.2006 Где: Moscow Репутация: 62 Всего: 128 |
что-то прям чудеса какие-то. на первый взгляд работа с мютексами вроде бы корректная.
-------------------- There are always someone smarter than you... |
|||
|
||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 38 Всего: 89 |
Может и глупость скажу, но... у вас процедура-1 и процедура-2 выполняются в разных потоках? Добавьте логгинг GetCurrentThreadId.
Если в одинаковых, то, скорее всего, ситуация выглядит как-то так: запускается процедура-1, берёт блокировку, где-то внутри себя вызывает Application.ProcessMessages (или аналог) - в этот момент запускается сидящая в очереди процедура-2, она работает, поскольку текущий поток уже владеет блокиовкой, процедура-2 завершается, затем заканчивается процедура-1 и отпускает блок. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
oleg153 |
|
|||
Новичок Профиль Группа: Участник Сообщений: 34 Регистрация: 1.3.2007 Репутация: нет Всего: нет |
Спасибо. Кое что понял
Я проверил - по Memo1.Lines.Add(inttostr(GetCurrentThreadId()); получается что поток один. Я из того что читал понял что VCL (основной поток) и поток COM - разные, даже если сервер создан как STA. Но похоже я ошибся. Значит все варианты блокировки с использованием секций и мьютексов не пройдут. Или нужно создавать отдельные потоки Но почему запускается Процедура-2 ? Ведь вроде смысл одного потока - ждать окончания 1-ой процедуры ? И что делать если НЕ разделять процедуры по разным потокам ? Как не позволить запускаться |
|||
|
||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 38 Всего: 89 |
Если вы привели полный код, то вот это у вас кто: DServ.Test1? Ещё ShowMessage содержит цикл Application.ProcessMessages (если это действительно причина). -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
oleg153 |
|
|||
Новичок Профиль Группа: Участник Сообщений: 34 Регистрация: 1.3.2007 Репутация: нет Всего: нет |
DServ - соответственно Сервер-3. Еще один сом-сервер также реализованый как STA (однопотоковый) , который производит обработку переданых ему в процедуре SetData1 - данных. В Данном примере я на сервере-3 просто организовал задержку и передаю время задержки. Это для тестирования. В реали я передаю данные которые обрабатываются 0.5-5 сек и возвращают результат обработки. Возврат не стал делать так как его наличие не влияет на результат, все равно в потоке после вызова DServ.Test1 начинает работать Процедура-2. Т.е. в основном потоке очередь от Процедуры-1 передается на П-2 хотя П-1 не отработалась до конца. К сожалению [B][Ещё ShowMessage содержит цикл Application.ProcessMessages (если это действительно причина)./B] - это мне не понятно. Если можно поясните. |
|||
|
||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 38 Всего: 89 |
Я, признаться, в COM полный 0, поэтому при ваших объяснениях сразу забуксовал. Давайте вам кто-нибудь другой что-нить скажет
![]() -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
Palladin |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 932 Регистрация: 15.5.2007 Где: Беларусь г.Гомель Репутация: 3 Всего: 17 |
Мдя, ну на крайняк:
Создаешь переменную, обнуляешь её, когда заканчивается первая процедура присваеваешь переменной, ну к примеру значение '1', а весь код второй процедуры заключаешь в
![]() Добавлено через 3 минуты и 41 секунду Не прочитал все, поэтому сверху чушь. Однако, вот ты передаешь значения в первой процедуре, во второй попробуй проверять, ну мол передалось ли последнее значение первой процедуры, если да то выполняем вторую процедуру, если нет... Получается тоже if(a=1) только вместо а проверяй мол ввелось ли или передалось ли чтонить... -------------------- Глуп тот кто полагается на истину авторитета, а не на авторитет истины [color=red]KAV&KIS==Evil[/color] |
|||
|
||||
MetalFan |
|
|||
![]() Аццкий Сотона ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3815 Регистрация: 2.10.2006 Где: Moscow Репутация: 62 Всего: 128 |
тогда примерно понятно. afaik STA реализуется с пом. очереди сообщений того потока, в котором работает ком-сервер. соотв. как только в одной процедуре начинается проверка очереди сообщений, а кто-то обращается к другой процедуре, то это другая процедура и начнет выполняться. да и мютексы и крит.секции в этом случае безполезны - это средства межпроцессовой и межпотоковой синхронизации. тогда действительно проще завести переменную-флаг, а еще лучше не пользовать ShowMessage, а пользовать какой-нибудь MessageBox или вообще писать в лог. -------------------- There are always someone smarter than you... |
|||
|
||||
oleg153 |
|
|||
Новичок Профиль Группа: Участник Сообщений: 34 Регистрация: 1.3.2007 Репутация: нет Всего: нет |
В общем вроде понял.
У меня был Сервер-2 однопотоковый. Соответственно ни секции ни мьютексы не работали. Сом-методы вызывались в основном, и захват Крит.секции этим потоком позволял выполнять как процедуры вызваные Сервером, так и через СОМ. Сделал его в модели Free - т.е. многопотоковым. Тогда Клинт и Сервер могут запускать одну процедуру в разных потоках и можно использовать крит. секцию. Но если в сом-потоке будет присутствовать обращение к VCL элементам Сервера-2 , тогда все просто встанет, так как для этого нужно передать управление основному потоку. Соответственно сом-поток ( в апартаменте) не может завершить действия. В общем , чтоб не городить флаги, придется делать многопотоковый сервер и просто внимательно следить за обращением к VCL-компонентам. Обращаться к ним только из основного потока, когда он владеет Крит.секцией. Пока на первый взгляд так должно работать. В вышеприведенном коде вроде работает. |
|||
|
||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 38 Всего: 89 |
Ну, для обращения к главному потоку из любого вторичного есть Synchronize (также и в статическом варианте), либо удобная оболочка для него EnterMainThread/LeaveMainThread из AsyncCalls.
-------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
oleg153 |
|
|||
Новичок Профиль Группа: Участник Сообщений: 34 Регистрация: 1.3.2007 Репутация: нет Всего: нет |
Если можно, проясните, сам пока не понял.
Есть Основной поток Сервера и COM-поток созданный Сервером Для исключения доступа к процедуре описаной в главной форме использую Крит. секцию. СОМ-поток захватывает секцию и работает с Таблицами (MSSQL) через ADO. Если в момент работы когда Крит.сек. захвачена Основной поток пытается запустить процедуру, он натыкается на блокировку через Крит.секс. и становится в ожидание. И вот если в этот момент активный СОМ-поток пытается что либо сделать с экранными компонентами (Memo, DBGrid ) - тогда все умирает. Совсем. Тупик. Понимаю что это из-за блокировки основного потока Критической секцией. Но поможет ли здесь Synchronize ? Ведь основной поток заблокирован на попытке EnterCriticalSection(CS); Подскажите, так как с потоками только разбираюсь и боюсь напортачить. |
|||
|
||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 38 Всего: 89 |
Мне просто показалось, что обе процедуры запускаются из вторичных потоков. А так, вы, конечно, правы - у вас будет dead-lock - два потока будут ждать друг-друга. Если из главного потока нужно запустить что-то, что требует блокировки, которую может держать другой поток, который может запросить главный поток, который живёт в доме, который построил джек, то лучше бы это "что-то" запустить в ещё одном отдельном потоке, дабы не блокировать главный. Блокировать главный поток в VCL-приложении - это не очень хорошо. Если пойдёте таким путём, то к вашим услугам Synchronize. Если же нет - то тут только отправка сообщений. Да и то, сообщение не будет обработано, пока главный поток блокирован. Так что, ситуация с dead-lock-ом может даже и повториться, если вы используете SendMessage. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
oleg153 |
|
|||
Новичок Профиль Группа: Участник Сообщений: 34 Регистрация: 1.3.2007 Репутация: нет Всего: нет |
Да. Спасибо.
Я Тоже прихожу к выводу что придется запускать в отдельном, не COM потоке. Теперь осталось внимательно разобратся с потоками. |
|||
|
||||
oleg153 |
|
|||
Новичок Профиль Группа: Участник Сообщений: 34 Регистрация: 1.3.2007 Репутация: нет Всего: нет |
Пока еще не понял как совместить Synchronize и ADO
Допустим в потоке нужно выполнить код :
Здесь ADOQuery через TDataSource отображает в таблице DBGrid результаты. Причем динамически. Это можно увязать с Synchronize ? |
|||
|
||||
![]() ![]() ![]() |
Правила форума "Delphi: Общие вопросы" | |
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |