Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Бесконфликтное многопоточное VCL-приложение, синхронизация 
:(
    Опции темы
Gradov
Дата 24.3.2009, 16:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 124
Регистрация: 31.10.2006

Репутация: 2
Всего: 3



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

В справке к компоненту TThread есть замечание:
Most methods that access a VCL object and update a form must only be called from within the main VCL thread or use a synchronization object such as TMultiReadExclusiveWriteSynchronizer.

Означает ли это, что любое обращение не из VCL потока к компонентам надо делать через объекты синхронизации? Т.е. установка свойств, например, Button1->Enabled, Label1->Caption и т.д., а также чтение и запись свойств таких компонентов как TTable, TQuery тоже надо обязательно через synchronize? Это ж тогда получатся один VCL-thread будет работать и все преимущество многопоточности потеряется!?

Код

while (!Table1->Eof)
{
  .....
}


Вот такое простое обращение к табличке надо ли оформлять через Synchronize не в VCL-потоке? Спрашиваю потому как это добавляет дополнительного гемороя, из-за того что метод Synchronize должен быть void-ным с обеих сторон. Т.е. вернуть значение нельзя, нужно будет использовать доп. переменную.

PS: когда код более 10000 сторок вот таких маленькие фрагменты задолбаешься переделывать. 


Это сообщение отредактировал(а) Gradov - 24.3.2009, 16:54
PM MAIL   Вверх
mrbrooks
Дата 24.3.2009, 16:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


трололомен
****


Профиль
Группа: Завсегдатай
Сообщений: 4259
Регистрация: 4.10.2006
Где: Дол Гулдур

Репутация: 167
Всего: 306



Gradov, рекомендуется любую работу с VCL классом в потоке TThread производить через метод Synchronize.
PM MAIL   Вверх
Gradov
Дата 24.3.2009, 16:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 124
Регистрация: 31.10.2006

Репутация: 2
Всего: 3



Что даже условие 
Код

while (!Table1->Eof)
?????
PM MAIL   Вверх
mrbrooks
Дата 24.3.2009, 16:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


трололомен
****


Профиль
Группа: Завсегдатай
Сообщений: 4259
Регистрация: 4.10.2006
Где: Дол Гулдур

Репутация: 167
Всего: 306



Gradov, если у тебя именно на цикле подвисает то не забудь сделать так:
Код

DataSourceForTable1->Enable = false;
while (!Table1->Eof)
{
//bla bla bla
}
DataSourceForTable1->Enable = true;

PM MAIL   Вверх
Alca
Дата 24.3.2009, 17:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 25
Всего: 50



Критические секции пробывал?


--------------------
PM WWW ICQ Skype Jabber   Вверх
Gradov
Дата 24.3.2009, 17:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 124
Регистрация: 31.10.2006

Репутация: 2
Всего: 3



Цитата(Alca @  24.3.2009,  17:11 Найти цитируемый пост)
Критические секции пробывал? 

Они не помогут в разрешении конфликтов доступа к VCL-компонентам. Поскольку насколько мне изветсно библиотека VCL-непотокобезопасна. Т.е. если я, например, код обращения к таблице оформлю через Critical Sections, то это будет одностороннее решение.

Цитата(mrbrooks @  24.3.2009,  16:59 Найти цитируемый пост)
Gradov, если у тебя именно на цикле подвисает то не забудь сделать так:


Но это все равно не решение. Потому как я много других вариантов приведу, которые я тоже не знаю делать через Synchronize или нет, например Button2->Enabled=false, Label5->Caption="Name45", Query4->SQL->Clear() и т.д.


PM MAIL   Вверх
Alca
Дата 24.3.2009, 17:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 25
Всего: 50



Цитата

то это будет одностороннее решение.

Эт как?


--------------------
PM WWW ICQ Skype Jabber   Вверх
Gradov
Дата 24.3.2009, 18:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 124
Регистрация: 31.10.2006

Репутация: 2
Всего: 3



Цитата(Alca @  24.3.2009,  17:31 Найти цитируемый пост)
Эт как? 


Ну я со своей стороны в критическую секцию заключу операторы, а в VCL нет. И, например, при перемещении по таблице во время выполнения моего потока, произойти может конфликт доступа 2-х потоков к объекту(моего и VCL).
PM MAIL   Вверх
mrbrooks
Дата 24.3.2009, 18:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


трололомен
****


Профиль
Группа: Завсегдатай
Сообщений: 4259
Регистрация: 4.10.2006
Где: Дол Гулдур

Репутация: 167
Всего: 306



Цитата(Gradov @  24.3.2009,  17:18 Найти цитируемый пост)
Но это все равно не решение. 

Обоснуй.
Цитата(Gradov @  24.3.2009,  17:18 Найти цитируемый пост)
Потому как я много других вариантов приведу, которые я тоже не знаю делать через Synchronize или нет, например Button2->Enabled=false, Label5->Caption="Name45", Query4->SQL->Clear() и т.д.

Приведи. 
Начнем с того что тот код который я тебе показал ни какого отношения к потокам не имеет. Это стандартная навигация по таблице, при чем при большом количестве данных. 

Судя по тому, что ты здесь написал, читай литературу по базам данных и потокам - прежде чем поучать других, что помогает, а что нет.

зы. Критические секции здесь действительно ни к чему.
PM MAIL   Вверх
Gradov
Дата 24.3.2009, 18:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 124
Регистрация: 31.10.2006

Репутация: 2
Всего: 3



Цитата(mrbrooks @  24.3.2009,  18:21 Найти цитируемый пост)
Судя по тому, что ты здесь написал, читай литературу по базам данных и потокам - прежде чем поучать других, что помогает, а что нет.


 smile  Да никого я вроде бы и не поучал...

Цитата(mrbrooks @  24.3.2009,  18:21 Найти цитируемый пост)
Начнем с того что тот код который я тебе показал ни какого отношения к потокам не имеет. Это стандартная навигация по таблице, при чем при большом количестве данных. 

 
Ну так а я тебя что просил мне показывать навигацию по таблице, при большом количестве данных??  smile 

Вопрос конкретно был задан: обращение на чтение к VCL-компонентам типа while(!Table1->Eof) нужно через synchronize делать не в VCL-потоке или нет - не будет при такои использовании конфликтов?
PM MAIL   Вверх
Alca
Дата 24.3.2009, 18:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 25
Всего: 50



Цитата

зы. Критические секции здесь действительно ни к чему

Исходник Synchronize:
Код

//---------------------------------------------------------------------------
procedure TThread.Synchronize(Method: TThreadMethod);
var
  SyncProc: TSyncProc;
begin
  if GetCurrentThreadID = MainThreadID then
    Method
  else
  begin
    SyncProc.Signal := CreateEvent(nil, True, False, nil);
    try
      EnterCriticalSection(ThreadLock);
      try
        FSynchronizeException := nil;
        FMethod := Method;
        SyncProc.Thread := Self;
        SyncList.Add(@SyncProc);
        ProcPosted := True;
        if Assigned(WakeMainThread) then
          WakeMainThread(Self);
        LeaveCriticalSection(ThreadLock);
        try
          WaitForSingleObject(SyncProc.Signal, INFINITE);
        finally
          EnterCriticalSection(ThreadLock);
        end;
      finally
        LeaveCriticalSection(ThreadLock);
      end;
    finally
      CloseHandle(SyncProc.Signal);
    end;
    if Assigned(FSynchronizeException) then raise FSynchronizeException;
  end;
end;
//---------------------------------------------------------------------------

 smile

Добавлено через 3 минуты и 57 секунд
Работа с потоками в Delphi: так ли страшен чёрт, как его малюют?

Это сообщение отредактировал(а) Alca - 24.3.2009, 18:47


--------------------
PM WWW ICQ Skype Jabber   Вверх
Gradov
Дата 24.3.2009, 19:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 124
Регистрация: 31.10.2006

Репутация: 2
Всего: 3



Alca, дело в том что критические секции не помогут при разрешении конфликтов доступа к VCL-компонентам. Я же не влезу в код VCL и не смогу вставить туда свою критическую секцию, согласен? Вот поэтому я и говорил об одностороннем решении.

Добавлено @ 19:20
Вот и ты ссылку удачно привел.
Но не всё так просто. Казалось бы - пишем любой код внутри метода Execute и всё, а нет, потоки имеют одно неприятное свойство - они ничего не знают друг о друге. И что такого? - спросите вы. А вот что: допустим, вы пытаетесь из другого потока изменить свойство какого-нибудь компонента на форме. Как известно, VCL однопоточна, весь код внутри приложения выполняется последовательно. Допустим, в процессе работы изменились какие-то данные внутри классов VCL, система отбирает время у основного потока, передаёт по кругу остальным потокам и возвращает обратно, при этом выполнение кода продолжается с того места, где приостановилось. Если мы из своего потока что-то меняем, к примеру, на форме, задействуется много механизмов внутри VCL (напомню, выполнение основного потока пока "приостановлено"), соответственно за это время успеют измениться какие-либо данные. И тут вдруг время снова отдаётся основному потоку, он спокойно продолжает своё выполнение, но данные уже изменены! К чему это может привести - предугадать нельзя. Вы можете проверить это тысячу раз, и ничего не произойдёт, а на тысяча первый программа рухнет. - Юрий Балыкин.

Это сообщение отредактировал(а) Gradov - 24.3.2009, 19:32
PM MAIL   Вверх
mrbrooks
Дата 24.3.2009, 19:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


трололомен
****


Профиль
Группа: Завсегдатай
Сообщений: 4259
Регистрация: 4.10.2006
Где: Дол Гулдур

Репутация: 167
Всего: 306



Цитата(Gradov @  24.3.2009,  18:40 Найти цитируемый пост)
Ну так а я тебя что просил мне показывать навигацию по таблице, при большом количестве данных?? 

Вообще-то нет  smile 
Цитата(Gradov @  24.3.2009,  18:40 Найти цитируемый пост)
Вопрос конкретно был задан: обращение на чтение к VCL-компонентам типа while(!Table1->Eof) нужно через synchronize делать не в VCL-потоке или нет - не будет при такои использовании конфликтов? 


ответ уже был:
Цитата(mrbrooks @  24.3.2009,  16:47 Найти цитируемый пост)
Gradov, рекомендуется любую работу с VCL классом в потоке TThread производить через метод Synchronize. 

Что тут еще добавить?
PM MAIL   Вверх
dumb
Дата 25.3.2009, 04:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


sceloglauxalbifacies
****


Профиль
Группа: Экс. модератор
Сообщений: 2929
Регистрация: 16.6.2006

Репутация: 32
Всего: 158



Gradov,
все визуальные компоненты можно считать небезопасными, а для не визуальных надо конкретно выяснять.
например, TTimer не визуален, но и не безопасен из-за используемой AllocateHWnd.

в твоем же случае, судя по всему, проблема в том, что для Table не выделена отдельная сессия. при работе с BDE правило такое: для каждого доп.потока - своя сессия, к которой следует привязывать компоненты, используемые в этом потоке.

ну и, конечно, с этой Table не стоит напрямую связывать компоненты отображения.
PM MAIL   Вверх
Gradov
Дата 25.3.2009, 12:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 124
Регистрация: 31.10.2006

Репутация: 2
Всего: 3



Цитата(dumb @  25.3.2009,  04:24 Найти цитируемый пост)
Gradov,все визуальные компоненты можно считать небезопасными, а для не визуальных надо конкретно выяснять.например, TTimer не визуален, но и не безопасен из-за используемой AllocateHWnd.

В общем лучше я так понял  перестраховаться и всё загнать в synchronize.

Цитата(dumb @  25.3.2009,  04:24 Найти цитируемый пост)
в твоем же случае, судя по всему, проблема в том, что для Table не выделена отдельная сессия

dumb, я использую разные компоненты TTable для каждого потока. Насколько мне известно каждый новый TTable имеет свою сессию. Т.е. лишний расход памяти на новый компонент тоже может быть выходом, верно?



PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) - крупнейший в рунете сборник материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C++ Builder | Следующая тема »


 




[ Время генерации скрипта: 0.1659 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.