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

Ваш аккаунт

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

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

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

Потоки. Synchronize -что за зверь такой и с чем едят?

590
28 июня 2007 года
Gigahard
223 / / 03.04.2006
Подскажите пожалуйста, для чего нужен метод класса TThread Synchronize? В книге по сабжу всего несколько строчек написано... Что то там про права доступа к VCL... Но ничего не понятно. Для чего собственно этот метод нужен и когда его нужно применять, а когда можно обойтись без него?
247
29 июня 2007 года
wanja
1.2K / / 03.02.2003
Чтобы VCL корректно обработало все, что хочет сделать с ее компонентами твой поток.
1
29 июня 2007 года
kot_
7.3K / / 20.01.2000
Цитата: Gigahard
Подскажите пожалуйста, для чего нужен метод класса TThread Synchronize? В книге по сабжу всего несколько строчек написано... Что то там про права доступа к VCL... Но ничего не понятно. Для чего собственно этот метод нужен и когда его нужно применять, а когда можно обойтись без него?


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

590
29 июня 2007 года
Gigahard
223 / / 03.04.2006
Synchronize нужно применять только в случае изменения компонентов формы или еще в случае обращения к пользовательским классам, созданным на VCL?

И еще вопросик...
Допустим у меня есть форма, на ней размещен компонент Memo
В исходнике, сначала я добавляю в memo строчку "До потока", потом создаю поток, который с некоторой задержкой добавляет в это Memo свою строку "из потока", а потом после вызова потока, в основном коде программы я добавляю в Memo третью строчку "после потока".
Нужно сделать так, чтоб третья строчка (после потока) не выводилась бы до того, как не закончит работу поточная функция.
Делал с Critical Section, но все равно, последняя строчка не дожидается вывода из потока.
Как можно с наименьшими ресурсными затратами организовать синхронизацию дополнительного и основного потока?
1
29 июня 2007 года
kot_
7.3K / / 20.01.2000
Цитата: Gigahard
Synchronize нужно применять только в случае изменения компонентов формы или еще в случае обращения к пользовательским классам, созданным на VCL?


Если класс является полем класса формы то для него тоже можно использовать Synchronize.

Цитата: Gigahard

И еще вопросик...
Допустим у меня есть форма, на ней размещен компонент Memo
В исходнике, сначала я добавляю в memo строчку "До потока", потом создаю поток, который с некоторой задержкой добавляет в это Memo свою строку "из потока", а потом после вызова потока, в основном коде программы я добавляю в Memo третью строчку "после потока".
Нужно сделать так, чтоб третья строчка (после потока) не выводилась бы до того, как не закончит работу поточная функция.
Делал с Critical Section, но все равно, последняя строчка не дожидается вывода из потока.
Как можно с наименьшими ресурсными затратами организовать синхронизацию дополнительного и основного потока?



Ну а в чем проблема - в основной функции потока перед завершением или посылай сообщение форме, или вызывай какую либо акцию. Найболее верно (просто) - послать форме сообщение о том что данный поток (функция) работу завершил. Все что для этого нужно - передать в функцию потока указатель на HWND.

1
29 июня 2007 года
kot_
7.3K / / 20.01.2000
Кроме того не забудь заглянуть в
{BCB}\CBuilder6\Examples\Apps\Threads
возможно многие ответы на вопросы ты там найдешь.
По посылке сообщений из потока на форуме примеры приводились неоднократно - поиск тебе в этом поможет. Поэтому код не считаю нужным приводить здесь еще раз.
590
29 июня 2007 года
Gigahard
223 / / 03.04.2006
Нет, я имел ввиду не визуальные компоненты формы, а VCL компоненты, такие как AnsiString и т.п. При обращении к пользовательским классам, которые используют подобные вещи, тоже нужно Synchronize применять?

Весь вопрос как приостановить выполнение основного кода программы, пока не будет выполнен код потока? Critical Section для этого существует или нет? Что то у меня не получается с ней синхронизировать поток с основным кодом. Если она не для этого, то на кой она вообще нужна?

Немного конкретики:
Я в отдельном потоке запускаю одну функцию (ф-ию поиска устройств). Она довольно ресурсоемкая и чтоб не загонять в ступор всю программу, я пускаю ее отдельным потоком. Но дело в том, что после вызова потока, дальнейший основной код должен работать с памятью, которая будет заполнена в коде потока. Соответственно нужно это дело как то синхронизировать, чтоб не было преждевременного обращения к незаполненной памяти...
В винде есть нечто типа WaitForSingleObject, но как эта фишка работает, что то не очень понятно...
1
30 июня 2007 года
kot_
7.3K / / 20.01.2000
Цитата: Gigahard
Нет, я имел ввиду не визуальные компоненты формы, а VCL компоненты, такие как AnsiString и т.п. При обращении к пользовательским классам, которые используют подобные вещи, тоже нужно Synchronize применять?


Я же на писал - по вашему желанию вы можете использовать Synchronize или любой другой способ обеспечения потокобезопасности. Задача - не дать возможность доступа к объекту более чем одного потока одновременно.

Цитата: Gigahard

Весь вопрос как приостановить выполнение основного кода программы, пока не будет выполнен код потока? Critical Section для этого существует или нет? Что то у меня не получается с ней синхронизировать поток с основным кодом. Если она не для этого, то на кой она вообще нужна?

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


Critical Section необходима для того что бы гарантировать возможность доступа к ресурсу только одного потока в процессе его работы. И до тех пор пока поток работу не закончит - данный ресурс не будет доступен для других в пределах секции естественно.
Функции ожидания (напр WaitForSingleObject) как раз и нужны для ситуаций ожидания освобождения ресурса. Для того чтобы было понятно как она работает - необходимо как минимум внимательно прочесть МСДН. Мне теорию излагать просто в облом - тем более что ради этого мне надо подняться c поломанной ногой к книжному шкафу на второй этаж - но я думаю вас не затруднит ввести в поисковике Рихтер и прочесть что он пишет. С него кстати (и с поиска по форуму) и надо начинать писать многопоточные приложения.

590
03 июля 2007 года
Gigahard
223 / / 03.04.2006
Итак немного результатов об экспериментах с синхронизацией.
Исходные данные такие: имеется форма, на ней размещены компоненты Memo и кнопка.
Основной код (Unit1.cpp):
Код:
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
        Form1->Memo1->Clear();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
Form1->Memo1->Clear();
Form1->Memo1->Lines->Add("Before thread"); //Выводим текст до создания потока
TestThread *tt=new TestThread(false); //Создаем и запускаем поток
/*
switch(WaitForSingleObject((HANDLE)tt->Handle, 5000))
{
    case WAIT_OBJECT_0:
    MessageBox(NULL, "Thread successfull", "", MB_OK);
    break;

    case WAIT_TIMEOUT:
    MessageBox(NULL, "Wait Timeout", "", MB_OK);
    break;

    case WAIT_FAILED:
    MessageBox(NULL, "Wait Failed", "", MB_OK);
    break;
}
*/
Form1->Memo1->Lines->Add("After thread"); //Дописываем после вызова потока
}

Код потока (Unit2.cpp)
Код:
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include "Unit2.h"

#pragma package(smart_init)
//---------------------------------------------------------------------------

__fastcall TestThread::TestThread(bool CreateSuspended)
        : TThread(CreateSuspended)
{
        this->FreeOnTerminate=true;
}
//---------------------------------------------------------------------------
void __fastcall TestThread::Execute()
{
        Synchronize(AddMemo);
        /* for(int i=0; i< 1000; i+=10)
        {
                Beep(i,25);
        }
        */
}
//---------------------------------------------------------------------------


void __fastcall TestThread::AddMemo()
{
        Form1->Memo1->Lines->Add("In thread");
}


По докам билдера, для доступа к компонентам главного потока VCL, нужно использовать метод Synchronize. Как он точно работает я честно говоря не знаю, но по идее должен приостанавливать главный поток и передавать управление потоку вызвавшему Synchronize.

Как можно увидеть в примере, сообщения выводятся в Memo не в порядке как они указаны в коде. Сначала добавляется запись "Before thread", потом "AfterThread" и уже третьей строкой добавляется "In Thread".
Получается, что вызываемый поток заканчивает свою работу позже, чем основной поток. При этом метод Synchronize не учитывает очередность.

Решил сделать с помощью Win API ожидание WaitForSingleObject. После вызова потока, передаю его хендл API функции ожидания...
Возникает несколько непонятных моментов.
Во первых, если в потоке при этом присутствует метод synchronize, то WaitForSingleObject заканчивается по таймауту. Происходит это видимо потому, что WaitForSingleObject приостанавливает работу главного VCL потока, а функция Synchronize, как раз должна обратиться к главному потоку. Чего не происходит, пока WaitForSingleObject не завершится по таймауту.
Во вторых, если в вызываемом потоке не использовать метод Synchronize, а просто загрузить его каким то долгим по исполнению кодом (см. закомментированый цикл с Beep), то WaitForSingleObject в итоге заканчивается успешно, но во время ожидания, главный поток не отрабатывает системные сообщения, т.е. форму нельзя не передвинуть, ни сделать что либо еще...

Как же сделать так, чтоб форма реагировала на сообщения, но при этом ждала бы завершения работы вызванного потока?

Да, забыл еще один вопрос... Может ли произойти так, что поток завершит работу и освободит свои ресурсы, до того, как его хендл передастся в функцию WaitForSingleObject? Что при этом делать?
590
07 июля 2007 года
Gigahard
223 / / 03.04.2006
Более менее разобрался с ожиданием завершения процесса, но осталось несколько непонятных моментов.
Для ожидания окончания работы процесса, используем функцию MsgWaitForMultipleObjects, с помощю которой отлавливаем так же и сообщения, которые потом обрабатываем через PeekMessage, TranslateMessage и DispatchMessage. Все это происходит в бесконечном цикле до момента завершения ожидаемого процесса...

Теперь собственно вопросы, насколько корректно использовать MsgWaitForMultipleObjects в бесконечном цикле ожидания? Не слишком ли это нагрузит процессор? Есть ли какой другой способ чтобы приостановить выполнение основного кода программы, до конца выполнения вызваного потока, но чтобы при этом сохранялась реакция интерфейса?
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог