Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.05.16;
Скачать: CL | DM;

Вниз

TThread.WaitFor   Найти похожие ветки 

 
Тимохов ©   (2004-04-28 10:39) [0]

При изучении потоков, как они организованы в windows, и просмотра кода класса TThread возникли следующие вопросы по указанному в названии вопроса методу:
1. Зачем в данном методе есть обработка случая, когда GetCurrentThreadID = MainThreadID? Разве главный поток также выполняется как TThread?
2. Зачем в waitfor есть sleep(0)? Что делает данная строка я знаю - говорит системе, что данный поток отказывается от отавшегося у него кванта времени. Зачем только это нужно не пойму.


 
Polevi ©   (2004-04-28 10:51) [1]

1.

 h:=TThread.Create(true);
 h.WaitFor;


 
Игорь Шевченко ©   (2004-04-28 10:58) [2]


> 2. Зачем в waitfor есть sleep(0)? Что делает данная строка
> я знаю - говорит системе, что данный поток отказывается
> от отавшегося у него кванта времени. Зачем только это нужно
> не пойму.


Чтобы дать возможность переключиться на другой поток - принудительный вызов планировщика потоков


 
MBo ©   (2004-04-28 11:01) [3]

2. чтобы другим потокам досталось побольше времени


 
NeyroSpace ©   (2004-04-28 11:01) [4]

Тогда и у меня вопрос пог теме:
Как управлять главным потоком?
Можно ли повысить понизить его приоритет и т.д. Как до него добраться средствами Delphi?


 
Digitman ©   (2004-04-28 11:10) [5]


> 1. Зачем в данном методе есть обработка случая, когда GetCurrentThreadID
> = MainThreadID? Разве главный поток также выполняется как
> TThread?


это для случая, когда при FreeOnTerminate = True поток вызывает свой собственный диструктор.. поток же не может ждать сам себя !

а вообще это большая засада - MainThreadId не всегда отражает Id осн.потока


 
Тимохов ©   (2004-04-28 11:11) [6]

Спасибо всем за проявленное внимание.
Но все же вопросы.


> Polevi ©   (28.04.04 10:51) [1]

Не понял вашего ответа - как это соотносится с вопросом.
Вы же создали доп поток и все, как это соотносится с обработкой случая для MainThreadId?


> Игорь Шевченко ©   (28.04.04 10:58) [2]
> MBo ©   (28.04.04 11:01) [3]

Про то, что sleep(0) делается для того, чтобы дургим потокам досталось времени я понимаю (сам примеро об этом сказал). Возникает вопрос - откуда такая забота дельфи о других потоках? Исходя из какой логики борланд заботится о других потоках именно в этом месте? Почему он в таком случае не делает этого в других местах?


 
Игорь Шевченко ©   (2004-04-28 11:15) [7]


> Почему он в таком случае не делает этого в других местах?


Наверное, потому что в других местах этого делать не нужно, не так ли ?


 
Тимохов ©   (2004-04-28 11:16) [8]


> Polevi ©   (28.04.04 10:51) [1]

Виноват - с помощью Digitman"a вроде понял, о чем вы говорили.

При постановке данного вопроса меня смутило то, что getcurrentthreadid, это не id потока в текущем объекте, а id потока, который вызывает данный метод.


 
Тимохов ©   (2004-04-28 11:18) [9]


> Игорь Шевченко ©   (28.04.04 11:15) [7]

Конечно так... в других значит не нужно.
Но вопрос то был почему именно в данном месте это нужно.

Насколько я понимаю и без этого будет работать.
Sleep(0) сделан в угоду некой оптимальности, смысл которой я понять не могу.


 
Digitman ©   (2004-04-28 11:22) [10]


> Sleep(0) сделан в угоду некой оптимальности


в Д5 нет никаких слипов в методе WaitFor

приведи тело метода - посмотрим что там к чему


 
Тимохов ©   (2004-04-28 11:24) [11]

function TThread.WaitFor: LongWord;
var
 H: THandle;
 WaitResult: Cardinal;
 Msg: TMsg;
begin
 H := FHandle;
 if GetCurrentThreadID = MainThreadID then
 begin
   WaitResult := 0;
   repeat
     { This prevents a potential deadlock if the background thread does a SendMessage to the foreground thread }
     if WaitResult = WAIT_OBJECT_0 + 1 then
       PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE);
     Sleep(0);
     CheckSynchronize;
     WaitResult := MsgWaitForMultipleObjects(1, H, False, 0, QS_SENDMESSAGE);
     Win32Check(WaitResult <> WAIT_FAILED);
   until WaitResult = WAIT_OBJECT_0;
 end else WaitForSingleObject(H, INFINITE);
 CheckThreadError(GetExitCodeThread(H, Result));
end;


 
Verg ©   (2004-04-28 11:35) [12]

1. Связано это с устройством синхронизатора в D6 и старше.
При ожидании завершения какого-либо потока, главный обязан производить циклическую обработку очереди синхронизации (CheckSynchronize). Кроме того, при этом он должен еще и производить обаботку очереди сообщений на предмет несобственных обращение к оконным процедурам (QS_SENDMESSAGE).
2. Sleep(0) Вставлен для того, чтобы дать остальным потокам, в том числе и тому, завершения которого он ждет дать квантов времени, если вдруг их приоритет меньше, чем у него самого. Обрати просто внимание на то, что MsgWaitForMultipleObjects вызывается с нулевым таймаутом и в цикле (вместе с CheckSynchronize)


 
Игорь Шевченко ©   (2004-04-28 11:35) [13]

Читать умеем ?
"Call CheckSynchronize periodically within the main thread in order for
  background threads to synchronize execution with the main thread."

Вот Sleep(0) и нужен, для того, чтобы дать возможность что-то сделать другим потокам.


 
Тимохов ©   (2004-04-28 11:55) [14]


> Verg ©   (28.04.04 11:35) [12]


> Вставлен для того, чтобы дать остальным потокам, в том числе
> и тому, завершения которого он ждет дать квантов времени,
> если вдруг их приоритет меньше

Здравая мысль.
Хотел было возразить вам: а почему борланд не использует SwitchToThread (у Рихтера 4изд. написано, что SwitchToThread лучше т.к. в отличие sleep дает потокам с низким приоритетом шанс на выполнение), но посмотрел на SwitchToThread и увидел, что он не поддерживается в win98.

Последний вопрос: как вы думаете, что будет если не будет sleep(0)? Варинты ответов: ответ (1) все будет работать, но возможно медленнее (2) возможно deadlocks


 
Verg ©   (2004-04-28 12:24) [15]


> Последний вопрос: как вы думаете, что будет если не будет
> sleep(0)?


Нужно анализировать, но, вероятно, и deadlock тоже может случится при определенных условиях. Все зависит от того, отдает ли MsgWaitFor кватны при нулевом таймауте. Точно не знаю.
Однако, хочу сказать, что вопросы "зачем борнлад сдлал так-то, а не иначе" я, лично, считаю некорретными.
1. Как хотел, так и сделал. У многих задач есть не единственная корректная реализация.
2. Не нужно забывать, что начиная с D6 борлад очень сильно заботился о кросс-платформе.

Возьми, к примеру, рализацию метода Synchronize в D4 -

procedure TThread.Synchronize(Method: TThreadMethod);
begin
 FSynchronizeException := nil;
 FMethod := Method;
 SendMessage(ThreadWindow, CM_EXECPROC, 0, Longint(Self));
 if Assigned(FSynchronizeException) then raise FSynchronizeException;
end;


ВСЕ! Восем строк.

Теперь от D6
procedure TThread.Synchronize(Method: TThreadMethod);
var
 SyncProc: TSyncProc;
begin
 if GetCurrentThreadID = MainThreadID then
   Method
 else
 begin
{$IFDEF MSWINDOWS}
   SyncProc.Signal := CreateEvent(nil, True, False, nil);
   try
{$ENDIF}
{$IFDEF LINUX}
     FillChar(SyncProc, SizeOf(SyncProc), 0);  // This also initializes the cond_var
{$ENDIF}
     EnterCriticalSection(ThreadLock);
     try
       FSynchronizeException := nil;
       FMethod := Method;
       SyncProc.Thread := Self;
       SyncList.Add(@SyncProc);
       ProcPosted := True;
       if Assigned(WakeMainThread) then
         WakeMainThread(Self);
{$IFDEF MSWINDOWS}
       LeaveCriticalSection(ThreadLock);
       try
         WaitForSingleObject(SyncProc.Signal, INFINITE);
       finally
         EnterCriticalSection(ThreadLock);
       end;
{$ENDIF}
{$IFDEF LINUX}
       pthread_cond_wait(SyncProc.Signal, ThreadLock);
{$ENDIF}
     finally
       LeaveCriticalSection(ThreadLock);
     end;
{$IFDEF MSWINDOWS}
   finally
     CloseHandle(SyncProc.Signal);
   end;
{$ENDIF}
   if Assigned(FSynchronizeException) then raise FSynchronizeException;
 end;
end;


Плюс процедура CheckSynchronize, плюс головняк ее вовремя и к месту вызывать.

Спрашивается - ЗАЧЕМ?


 
Verg ©   (2004-04-28 12:29) [16]

Плюс в D6 реализации CheckSynchronize есть один глючок, который может приводить к AV в на первый взгляд безобидной ситуации.


 
Тимохов ©   (2004-04-28 12:35) [17]


> 1. Как хотел, так и сделал. У многих задач есть не единственная
> корректная реализация.

Согласен.

Поясню зачем все это нужно и почему мне это интересно:
1. Я нисколько не наезжаю на боланд - дельфи это хорошо.
2. Но когда я прийду (например) на собеседование к Юрию Зотову он мне задаст первый вопрос:

какое значение отладчик покажет на строк showmessage для переменной I на шаге 8 в коде
for I := 1 to 10 do
  ShowMessage("1")

и второй: зачем sleep в waitfor.

Оба этих вопроса по мнению специалиста по кадрам говорят о глубине знаний.

Вот мне и хочется - не ударить лицом в грязь.

:))

Всем спасибо.


 
Тимохов ©   (2004-04-28 12:35) [18]

Удалено модератором
Примечание: Дубль


 
Игорь Шевченко ©   (2004-04-28 13:27) [19]


> и второй: зачем sleep в waitfor.


Я бы честно ответил - надо по коду посмотреть


 
Тимохов ©   (2004-04-28 13:35) [20]


> Игорь Шевченко ©   (28.04.04 13:27) [19]

конечно по коду - как без него.

А что отвечать на вопрос - а если убрать sleep(0) что будет?
Не хочется же лицом в грязь перед уважаемыми людьми :))

В общем будем разбираться...



Страницы: 1 вся ветка

Текущий архив: 2004.05.16;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.028 c
3-1082283525
Viktor
2004-04-18 14:18
2004.05.16
ограничение кол-ва записей


4-1079947689
Rem
2004-03-22 12:28
2004.05.16
Что такое OLE_HANDLE?


3-1082379567
European
2004-04-19 16:59
2004.05.16
Рекурсивный иерархический SQL-запрос


6-1080208521
Valentin
2004-03-25 12:55
2004.05.16
нужен модуль


14-1082886479
Oyster
2004-04-25 13:47
2004.05.16
День программиста