Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.60/47: Рейтинг темы: голосов - 47, средняя оценка - 4.60
16 / 16 / 10
Регистрация: 13.02.2013
Сообщений: 75

Разница между TThread::WaitFor и WaitForSingleObject

01.12.2015, 17:31. Показов 9146. Ответов 17
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток!
Имеется код:

Главный модуль
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//Main.cpp
 
HANDLE hMyThread = NULL;
TThread* MyThread = NULL;
 
bool Check_hMyThread(HANDLE hThread)
{
    DWORD lpExitCode;
    if (GetExitCodeThread(hThread, &lpExitCode))
    {
        if (lpExitCode == STILL_ACTIVE)
        {
          return true;
        }
    }
    return false;
}
 
 
void __fastcall TForm2::Button1Click(TObject *Sender)
{
   MyThread = new Test(true);
   MyThread->FreeOnTerminate = false;
   MyThread->Priority = tpNormal;
 
   DuplicateHandle
   (
    GetCurrentProcess(),
    (HANDLE)MyThread->Handle,
    GetCurrentProcess(),
    &hMyThread,
    0,
    FALSE,
    DUPLICATE_SAME_ACCESS
   );
 
   MyThread->Resume();
 
}
 
void __fastcall TForm2::FormClose(TObject *Sender, TCloseAction &Action)
{
    if (Check_hMyThread(hMyThread))
    {
       MyThread->Terminate();
       WaitForSingleObject(hMyThread, INFINITE); //MyThread->WaitFor(); или WaitForSingleObject(hMyThread, INFINITE);
       delete MyThread;
    }
}

И модуль потока
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Thread.cpp
 
void __fastcall Test::Execute()
{
    while (!this->Terminated)
    {
       Sleep(7000);
       Synchronize(&UpdateCaption);
    }
 
}
 
void __fastcall Test::UpdateCaption()
{
    Form2->Caption = "Updated in a thread";
}
В обработчике Button1Click создается и запускается поток, который посредством синхронизации обновляет caption формы каждые 7 секунд. В деструкторе формы этот поток уничтожается.

Собственно вопрос и внимание на 46 строку кода - Если попытаться закрыть форму, пока 7 секунд еще не прошли и воспользоваться функцией WaitForSingleObject(); для ожидания завершения потока, то форма повиснит намертво и это вполне логично, потому что дополнительный поток стоит в очереди и ждет когда освободится главный поток, чтобы войти в synchonize, а главный поток тем временем занят залипанием, в ожидание завершения дополнительного потока, в общем замкнутый круг и это состояние вполне естественное. Но не могу понять, почему если WaitForSingleObject(); заменить на WaitFor() и проделать выше описанные действия, то WaitFor() уступит место дополнительному потоку и весь код в synchonize корректно выполнится и форма закроется?
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
01.12.2015, 17:31
Ответы с готовыми решениями:

Разница между *.res и *.rc
Опишите разницу между *.res и *.rc файлами, преимущества.

Разница между версиями C++ Builder
Здрасте всем. Вопрос по версиям Builder. Чем отличаются программы, написанные на C++ Builder 6 от программ на Embarcadero? ...

В чем разница между MSVC2010 и MSVC2013?
Приветствую! В чем разница между MSVC2010 и MSVC2013? В чем и где это может проявиться? Что стало лучше в, наверно, следующей версии...

17
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
01.12.2015, 17:56
Лучший ответ Сообщение было отмечено SatanaXIII как решение

Решение

Нужно смотреть в исходники на делфях

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function TThread.WaitFor: LongWord;
var
  H: array[0..1] of THandle;
  WaitResult: Cardinal;
  Msg: TMsg;
begin
  if FExternalThread then
    raise EThread.CreateRes(@SThreadExternalWait);
  H[0] := FHandle;
  if CurrentThread.ThreadID = MainThreadID then
  begin
    WaitResult := 0;
    H[1] := SyncEvent;
    repeat
      { This prevents a potential deadlock if the background thread
        does a SendMessage to the foreground thread }
      if WaitResult = WAIT_OBJECT_0 + 2 then
        PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE);
      WaitResult := MsgWaitForMultipleObjects(2, H, False, 1000, QS_SENDMESSAGE);
      CheckThreadError(WaitResult <> WAIT_FAILED);
      if WaitResult = WAIT_OBJECT_0 + 1 then
        CheckSynchronize;
    until WaitResult = WAIT_OBJECT_0;
  end else WaitForSingleObject(H[0], INFINITE);
  CheckThreadError(GetExitCodeThread(H[0], Result));
end;
Из кода видим что ожидание с таймаутом и ожидается не только поток, но еще и событие SyncEvent отвечающие за синхронизацию с главным потоком.
1
16 / 16 / 10
Регистрация: 13.02.2013
Сообщений: 75
01.12.2015, 17:58  [ТС]
Цитата Сообщение от Avazart Посмотреть сообщение
Нужно смотреть в исходники на делфях
Спасибо, жаль мои знания дельфи не позволяют реализовать подобное на C++. Тк мне принципиально чтобы FreeOnTerminate был равен true, при этом возможность завершить его в любое время. Эх Прийдется прибегнуть к TerminateThread + WaitForSingleObject
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
01.12.2015, 18:04
Я для FreeOnTerminate=true использую событие OnTerminate в нем обнуляю указатель на поток, если мне нужно обратиться из главного потока во вторичный я просто проверяю для начала указатель.
0
16 / 16 / 10
Регистрация: 13.02.2013
Сообщений: 75
01.12.2015, 18:04  [ТС]
Цитата Сообщение от Avazart Посмотреть сообщение
Из кода видим что ожидание с таймаутом и ожидается не только поток, но еще и событие SyncEvent отвечающие за синхронизацию с главным потоком.
За это спасибо, щас будем разбираться)
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
01.12.2015, 18:07
Смотрите Проверка существования потока
0
16 / 16 / 10
Регистрация: 13.02.2013
Сообщений: 75
01.12.2015, 18:13  [ТС]
Цитата Сообщение от Avazart Посмотреть сообщение
Я использую событие FreeOnTerminate=true, а в событии OnTerminate обнуляю указатель на поток, если мне нужно обратиться из главного потока во вторичный я просто проверяю для начала указатель.
ну а если на момент проверки объект уже будет разрушен?
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
01.12.2015, 18:16
Цитата Сообщение от alexeyj Посмотреть сообщение
ну а если на момент проверки объект уже будет разрушен?
Если на данный момент осуществляется выполнение какой либо функции в основном потоке(основной поток занят выполнение какой либо работы), то вторичный поток не сможет завершится пока эта функция полностью не выполнится из-за необходимости синхронизации при выходе из потока.Как только ф-ция выполнится и основной поток освободится сможет выполнится OnTerminate (в контексте основного потока) и обнулить указатель на поток.

Т.е. когда выполняется к примеру кнопка "стоп" можно смело утверждать о состоянии потока по указателю на вторичный поток.
1
16 / 16 / 10
Регистрация: 13.02.2013
Сообщений: 75
01.12.2015, 18:29  [ТС]
Цитата Сообщение от Avazart Посмотреть сообщение
Если на данный момент осуществляется выполнение какой либо функции в основном потоке, то вторичный поток не сможет завершится пока эта функция полностью не выполнится из-за необходимости синхронизации при выходе из потока.
Т.е. когда выполняется к примеру кнопка стоп можно смело утверждать о состоянии потока по указателю на поток.
Допустим программа порождает Nое количество потоков, время работы которых будет зависеть от каких-либо условий. И тут мы решили закрыть программу. Мы не знаем сколько времени проработал какой-либо из потоков, мы не знаем какой из них валидный, а какой нет, мы лишь имеет вектор указателей на раннее созданные потоки..

Каков выход? Проверка на OnTerminate != NULL тут явно не покатит..

Забыл добавить, что все это при условии, что
C++
1
FreeOnTerminate=true
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
01.12.2015, 18:44
Цитата Сообщение от alexeyj Посмотреть сообщение
мы не знаем какой из них валидный, а какой нет,
Как не знаем, есть же
Цитата Сообщение от alexeyj Посмотреть сообщение
вектор указателей на раннее созданные потоки..
1
16 / 16 / 10
Регистрация: 13.02.2013
Сообщений: 75
01.12.2015, 18:44  [ТС]
Цитата Сообщение от Avazart Посмотреть сообщение
и основной поток освободится сможет выполнится OnTerminate (в контексте основного потока) и обнулить указатель на поток.
до меня немного дошло)
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
01.12.2015, 23:43
Чего тут доходить? Я ссылку на код примера указал выше.

Но лучше конечно попросту отказаться от FreeOnTerminate=true, что бы избежать удаления потока и не парится насчет дедлоков которые могут быть при OnTerminate

Добавлено через 4 часа 47 минут
Кстати есть неплохая статейка Многопоточные программы в Delphi изнутри 2009г Андрей Боровский
К примеру что бы избежать дедлоков можно попробовать заменить Synchronize() на Queue() (Я обычно использую TIdNotify) в вашем коде.
1
16 / 16 / 10
Регистрация: 13.02.2013
Сообщений: 75
03.12.2015, 16:42  [ТС]
По поводу обнуления указателя в событие OnTerminate
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function ThreadProc(Thread: TThread): Integer;
var
   FreeThread: Boolean;
begin
   try
     if not Thread.Terminated then
       try
         Thread.Execute;
       except
         Thread.FFatalException := AcquireExceptionObject;
       end;
   finally
     FreeThread := Thread.FFreeOnTerminate;
     Result := Thread.FReturnValue;
     Thread.FFinished := True;
     Thread.DoTerminate;
     if FreeThread then Thread.Free;
     EndThread(Result);
   end;
end;
на 16ой строке происходит вызов события OnTerminate в котором предполагается обнуление указателя.
на 17ой строке проверяется, установили ли мы флаг FreeOnTerminate в true, если да, то произойдет попытка очистить уже раннее освобожденный регион памяти, но даже если значение этого флага будет false, потом мы даже вручную не сможем освободить память, из этого предполагается единственный вариант, это установка флага в false и очистка памяти прям в обработчике. Правильно?
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
03.12.2015, 17:00
Цитата Сообщение от alexeyj Посмотреть сообщение
Правильно?
Нет.
Цитата Сообщение от alexeyj Посмотреть сообщение
в котором предполагается обнуление указателя.
Цитата Сообщение от alexeyj Посмотреть сообщение
то произойдет попытка очистить уже раннее освобожденный регион памяти,
Обнулить указатель не означает освобождение памяти из под объекта на который он указывает.
1
16 / 16 / 10
Регистрация: 13.02.2013
Сообщений: 75
03.12.2015, 18:09  [ТС]
Тогда встречный вопрос. Возможно ли как-то переопределить OnTerminate, чтобы в него была возможность передавать указатель на указатель объекта потока, чтобы бы не плодить обработчики для каждого объекта?
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
03.12.2015, 18:48
Так там же есть Sender ?
0
16 / 16 / 10
Регистрация: 13.02.2013
Сообщений: 75
03.12.2015, 19:24  [ТС]
Цитата Сообщение от Avazart Посмотреть сообщение
Так там же есть Sender ?
в том то и дело, что происходит копирование указателя в Sender. А мне нужно адрес первоначального указателя получать. В грубом исполнении выглядит так
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void __fastcall OnTerminate(TThread** obj)
{
  delete *obj;
  *obj = NULL;
}
 
__fastcall TForm2::TForm2(TComponent* Owner)
    : TForm(Owner)
{
 TThread* t = new Thread(true);
 t->FreeOnTerminate = false;
 //....
 OnTerminate(&t);
}
Добавлено через 9 минут
Замысел в том, чтобы обработчик был универсальным
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
03.12.2015, 19:59
Цитата Сообщение от alexeyj Посмотреть сообщение
Замысел в том, чтобы обработчик был универсальным
Это мудацтво.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
03.12.2015, 19:59
Помогаю со студенческими работами здесь

В чем разница между способами передачи структуры в функцию?
Доброго времени суток. Заинтересовывал вот такой вопрос, а именно в чем разница между способами передачи структуры в функцию? struct...

В чем разница между классами TWinControl, TControl, TComponent?
Вопрос в названии темы.

Какая разница между различными сокетами (например, между 775 и 1155)?
Обясните пожалуйста какая разница между сокетами, пример есть сокет 775 и 1155 я понимаю что разем не тот процессора другие но! как насчет...

waitfor() или чтото другое?
Здраствуйте. Я новичок в java программировании. у меня есть сервлет, который обрабатывает инфу полученую с РНР. Мне нужно написать код,...

Разница между 42.1 и 13.2?
Смотрел на сайте две версии 42.1 только 64 битные, а 13.2 и 32 и 64, но разницы не могу понять, что только биты? Добавлено через 2...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Новые блоги и статьи
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это дополнительная запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru