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

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

01.12.2015, 17:31. Показов 9066. Ответов 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
8484 / 6151 / 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
8484 / 6151 / 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
8484 / 6151 / 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
8484 / 6151 / 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
8484 / 6151 / 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
8484 / 6151 / 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
8484 / 6151 / 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
8484 / 6151 / 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
8484 / 6151 / 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
Ответ Создать тему
Новые блоги и статьи
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка. Рецензия / Мнение/ Перевод https:/ / **********/ gallery/ thinkpad-x220-tablet-porn-gzoEAjs . . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru