![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Ожидание начала работы нити.
Riply © (2007-01-04 02:45:00)Здравствуйте !
Мне надо убедиться, что нить приступила к работе.
Пытаюсь делать, примерно, так:
function ReallyStartedThread(const pParam: PThreadParam): DWord;
var
Msg: TMsg;
begin
Result := 0;
while GetMessage(Msg, 0, 0, 0) do
if Msg.message = REQUEST_EXISTS then Break else Sleep(0);
// .....
end;
function BeginRealStartThread(const aMode: DWord): Boolean;
var
hThread, ThreadID: DWord;
begin
Result := False;
hThread := BeginThread(nil, 0, @ReallyStartedThread, nil, 0, ThreadID);
if hThread <> 0 then
try
while not PostThreadMessage(ThreadID, REQUEST_EXISTS, 0, 0) do
if WaitForSingleObject(hThread, 1) <> WAIT_TIMEOUT then Exit;
Result := True;
finally
CloseHandle(hThread);
end;
end;
Могу ли я быть уверена, что не останусь в цикле навсегда ?
Или стоит предупредить близких, чтобы "не поминали лихом" ? :)
Джо (2007-01-05 15:54:00) [1]> [25] TUser © (05.01.07 14:33)
> В конструкторе TThread'а создать какой-нибудь мьютекс, а
> в Execute - освободить его.
У нас тутBeginThread:)
TUser (2007-01-05 14:33:00) [2]В конструкторе TThread'а создать какой-нибудь мьютекс, а в Execute - освободить его.
Riply (2007-01-05 06:23:00) [3]> [23] Джо © (05.01.07 06:04)
Ничего страшного: я сразу увидела эту описку, так что не пострадала :))
Джо (2007-01-05 06:04:00) [4]> GetMem (StartInfo,SizeOf(StartInfo));
Ай, какой ляп. Прошу прощения.
Джо (2007-01-05 02:27:00) [5]> Так, что Джо был абсолютно прав (если мы не оспариваем Рихтера)
> ,
> предлагая "хитро чесать пятку" используя Event, а не общую
> переменную. :))
Хитро чесать пятку тоже нужно со знанием. 8^)
Riply (2007-01-05 02:21:00) [6]Может кому - нибудь будет интересно.
Джеффри РИХТЕР
Худшее, что можно сделать.
Если бы синхронизирующих объектов не было, а операционная система
не умела отслеживать особые события, потоку пришлось бы самостоятельно
синхронизировать себя с ними, применяя метод, который я как раз и
собираюсь продемонстрировать. Но поскольку в операционную систему встроена
поддержка синхронизации объектов, никогда не применяйте этот метод.
Суть его в том, что поток синхронизирует себя с завершением какой-либо задачи
в другом потоке, постоянно просматривая значение переменной, доступной обоим
полкам Возьмем пример
volatile BOOL q_fFinishedCalculation = FALSE;
int WINAPI WinMain( )
{
CreateThread( , RecalcFunc, );
... // ждем завершения пересчета
while (!g_fFinishedCalculation)
...
}
DWORD WINAPI RecalcFunc(PVOID pvParam)
{ // выполняем пересчет
g_fFinishedCalculation = TRUE;
return(0);
}
Как видите, первичный поток (он исполняет функцию WinMain) при синхронизации
по такому событию, как завершение функции RecalcFunc, никогда не впадает в
спячку, Поэтому система по-прежнсму выделяет ему процессорное время за счет
других потоков, занимающихся чем-то более полезным.
Другая проблема, связанная с подобным методом опроса, в том, что булева переменная
g_fFinishedCalculation может не получить значения TRUE — например, если у первичного
потока более высокий приоритет, чем у потока, выполняющего функцию RecalcFunc.
В этом случае система никогда не предоставит процессорное время потоку RecalcFunc,
а он никогда не выполнит оператор, присваивающий значение TRUE переменной
g_fFinishedCalculation Если бы мы не опрашивали поток, выполняющий функцию WinMain,
а просто отправили в спячку, это позволило бы системе отдать его долю процессорного
времени потокам с более низким приоритетом, в частности потоку RecalcFunc.
Так, что Джо был абсолютно прав (если мы не оспариваем Рихтера),
предлагая "хитро чесать пятку" используя Event, а не общую переменную. :))
Riply (2007-01-04 19:02:00) [7]>[16] Джо © (04.01.07 08:06)
>Можно вообще ничего явно не ждать
Спасибо. Видимо подобным образом ("подобным" - т.к. формы нет) и поступлю.
>[19] Loginov Dmitry © (04.01.07 09:22)
>Rslt := WaitForSingleObject(hEvent,0);
hEvent - это хэндел события или нити ?
Правда и том, и в другом случае не понимаю: как это может помочь ?
Loginov Dmitry (2007-01-04 09:22:00) [8]> По моей задаче надо убедиться только в том,
Rslt := WaitForSingleObject(hEvent,0);
Джо (2007-01-04 08:33:00) [9]> [17] MsGuns © (04.01.07 08:19)
> И все-таки я не въехал зачем так хитро чесать пятку
Лично я люблю перед сном хитро почесать пятку :)
MsGuns (2007-01-04 08:19:00) [10]И все-таки я не въехал зачем так хитро чесать пятку ? Ученик ИМХО предложил простое и надежное решение - в основном потоке (модуле) создать некий объект, указатель на который передать потоку. В этом объекте вторичный поток пусть пишет чего хочет, а осн.поток через таймер (например) периодически его (объект) проверяет.
Всего делов-то
Джо (2007-01-04 08:06:00) [11]Можно вообще ничего явно не ждать, а выполнять нужные нам действия в отдельной процедуре после старта нити, т.е., в таком роде:
const
WM_THREAD_START = WM_USER + 666;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
procedure OnThreadStart (var Msg: TMessage); message WM_THREAD_START;
end;
implementation
type
TMessageStartInfo = record
MsgId: DWord;
WinHandle: THandle;
end;
PMessageStartInfo = ^TMessageStartInfo;
function ReallyStartedThread(StartInfo: PMessageStartInfo): DWord;
begin
PostMessage (StartInfo^.WinHandle,StartInfo^.MsgId,0,0);
FreeMem (StartInfo);
Result := 0;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
hThread: THandle;
ThreadID: DWord;
StartInfo: PMessageStartInfo;
begin
GetMem (StartInfo,SizeOf(StartInfo));
StartInfo^.MsgId := WM_THREAD_START;
StartInfo^.WinHandle := Handle;
hThread := BeginThread(nil, 0, @ReallyStartedThread, StartInfo, 0, ThreadID);
if hThread <> 0 then
begin
end
else
FreeMem (StartInfo);
end;
procedure TForm1.OnThreadStart(var Msg: TMessage);
begin
ShowMessage ('Started');
// Выполняем действия, какие нам нужны после старта нити
end;
Riply (2007-01-04 08:03:00) [12]По моей задаче надо убедиться только в том,
что нить приступила к работе (а не висит в процессе создания) и идти дальше.
А она пусть делает све дело :)
Джо (2007-01-04 07:56:00) [13]> [13] Riply © (04.01.07 07:50)
> >[12] Джо © (04.01.07 07:46)
> Вот и хочется определиться, когда должно наступить "Задолбался
> ждать" :))
> Сколько времени надо положить на это ?
А мне откуда знать, сколько по твоей задаче ждать положено? :)
Riply (2007-01-04 07:50:00) [14]>[12] Джо © (04.01.07 07:46)
Вот и хочется определиться, когда должно наступить "Задолбался ждать" :))
Сколько времени надо положить на это ?
Джо (2007-01-04 07:46:00) [15]> [10] Джо © (04.01.07 07:38)
> > [8] Ученик чародея © (04.01.07 05:53)
> > В начале выполнения нити какую-то "видимую" переменную
> выставляем
> > в true, ее и проверяем..?
>
> Не лучше ли CreateEvent, SentEvent и WaitForSingleObject?
Т.е., я имею в виду что-то в таком роде:
function ReallyStartedThread(Param: Pointer): DWord;
var
Msg: TMsg;
hEvent: THandle;
begin
hEvent := OpenEvent(EVENT_ALL_ACCESS,False,'MyThreadEvent');
if hEvent <> 0 then
begin
SetEvent (hEvent);
CloseHandle (hEvent);
end;
Result := 0;
end;
---
hEvent := CreateEvent(nil,False,False,'MyThreadEvent');
hThread := BeginThread(nil, 0, @ReallyStartedThread, nil, 0, ThreadID);
if hThread <> 0 then
begin
Rslt := WaitForSingleObject(hEvent,10000);
case Rslt of
WAIT_OBJECT_0: ShowMessage ('Thread started');
WAIT_TIMEOUT: ShowMessage ('Задолбался ждать');
end;
end;
CloseHandle (hEvent);
Riply (2007-01-04 07:45:00) [16]> [10] Джо © (04.01.07 07:38)
>Не лучше ли CreateEvent, SentEvent и WaitForSingleObject?
:)) И здесь тоже самое:
Не удается нам удрать от этого вопроса:
WaitForSingleObject(hEvent, ... INFINITE ?
А мы вернемся ? Если не INFINITE, то сколько времени положим на ожидание ?
Джо (2007-01-04 07:38:00) [17]> [8] Ученик чародея © (04.01.07 05:53)
> В начале выполнения нити какую-то "видимую" переменную выставляем
> в true, ее и проверяем..?
Не лучше ли CreateEvent, SentEvent и WaitForSingleObject?
Riply (2007-01-04 07:36:00) [18]>[8] Ученик чародея © (04.01.07 05:53)
>В начале выполнения нити какую-то "видимую" переменную выставляем в true, ее и проверяем..?
Здесь возникает тот же вопрос:
Есть уверенность, что не зависнем в цикле ?
function ThreadFunction(pParam: Pointer): DWord;
begin
IsStarted := True;
//...
end;
//...
IsStarted := False;
hThread := BeginThread(nil, 0, @ThreadFunction, nil, 0, ThreadID);
if hThread <> 0 then
while not IsStarted do Sleep(10);
//...
Ученик чародея (2007-01-04 05:53:00) [19]
> Riply © (04.01.07 05:20) [7]
>
> >[6] Tirael © (04.01.07 04:55)
> >а зачем PostThreadMessage и цикл?
> >просто
> >WaitForSingleObject(hThread, INFINITE);
> Нужно дождаться не завершения нити (она может работать и
> до потопа),
> а "начала выполнения кода в ее теле"
В начале выполнения нити какую-то "видимую" переменную выставляем в true, ее и проверяем..?
Riply (2007-01-04 05:20:00) [20]>[6] Tirael © (04.01.07 04:55)
>а зачем PostThreadMessage и цикл?
>просто
>WaitForSingleObject(hThread, INFINITE);
Нужно дождаться не завершения нити (она может работать и до потопа),
а "начала выполнения кода в ее теле"