Форум: "Начинающим";
Текущий архив: 2007.01.21;
Скачать: [xml.tar.bz2];
ВнизОжидание начала работы нити. Найти похожие ветки
← →
Riply © (2007-01-04 02:45) [0]Здравствуйте !
Мне надо убедиться, что нить приступила к работе.
Пытаюсь делать, примерно, так:
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;
Могу ли я быть уверена, что не останусь в цикле навсегда ?
Или стоит предупредить близких, чтобы "не поминали лихом" ? :)
← →
Riply © (2007-01-04 02:46) [1]Извините, опять забыла выделить код :(
← →
Ученик чародея © (2007-01-04 03:00) [2]Написать процедуру, которая проверяет какую-то "глобальную внутри объекта" флаговую переменную, отнимает значение времени от таймоута ожидания и делает между проверками Sleep(0) - передача неиспользованного кванта времени системе.
← →
Джо © (2007-01-04 03:18) [3]Самое простое, кажется — передавать ссылку на свою callback-процедуру, кою и вызывать, когда нужно.
← →
Джо © (2007-01-04 03:20) [4]Кажется, я неверно понял вопрос, сорри.
← →
Riply © (2007-01-04 04:21) [5]>[4] Джо © (04.01.07 03:20)
>Кажется, я неверно понял вопрос, сорри.
Это я плохо сформулировала :(
Попробую еще раз.
Нужно дождаться момента окончания "создания нити" и
начала выполнения кода в ее теле. Не знаю как еще сказать.
Я жду таким образом:while not PostThreadMessage(ThreadID, REQUEST_EXISTS, 0, 0) do
if WaitForSingleObject(hThread, 1) <> WAIT_TIMEOUT then Exit;
Но опасаюсь зависнуть в этом цикле :(
← →
Tirael © (2007-01-04 04:55) [6]а зачем PostThreadMessage и цикл?
простоWaitForSingleObject(hThread, INFINITE);
ведь он же запустится когданить, а если что то BeginThread сама выбросит эксцепшн, ибоBeginThread sets up an exception frame that allows the system"s default exception handler to catch any of the thread"s exceptions that have not been handled.
← →
Riply © (2007-01-04 05:20) [7]>[6] Tirael © (04.01.07 04:55)
>а зачем PostThreadMessage и цикл?
>просто
>WaitForSingleObject(hThread, INFINITE);
Нужно дождаться не завершения нити (она может работать и до потопа),
а "начала выполнения кода в ее теле"
← →
Ученик чародея © (2007-01-04 05:53) [8]
> Riply © (04.01.07 05:20) [7]
>
> >[6] Tirael © (04.01.07 04:55)
> >а зачем PostThreadMessage и цикл?
> >просто
> >WaitForSingleObject(hThread, INFINITE);
> Нужно дождаться не завершения нити (она может работать и
> до потопа),
> а "начала выполнения кода в ее теле"
В начале выполнения нити какую-то "видимую" переменную выставляем в true, ее и проверяем..?
← →
Riply © (2007-01-04 07:36) [9]>[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 07:38) [10]> [8] Ученик чародея © (04.01.07 05:53)
> В начале выполнения нити какую-то "видимую" переменную выставляем
> в true, ее и проверяем..?
Не лучше ли CreateEvent, SentEvent и WaitForSingleObject?
← →
Riply © (2007-01-04 07:45) [11]> [10] Джо © (04.01.07 07:38)
>Не лучше ли CreateEvent, SentEvent и WaitForSingleObject?
:)) И здесь тоже самое:
Не удается нам удрать от этого вопроса:
WaitForSingleObject(hEvent, ... INFINITE ?
А мы вернемся ? Если не INFINITE, то сколько времени положим на ожидание ?
← →
Джо © (2007-01-04 07:46) [12]> [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:50) [13]>[12] Джо © (04.01.07 07:46)
Вот и хочется определиться, когда должно наступить "Задолбался ждать" :))
Сколько времени надо положить на это ?
← →
Джо © (2007-01-04 07:56) [14]> [13] Riply © (04.01.07 07:50)
> >[12] Джо © (04.01.07 07:46)
> Вот и хочется определиться, когда должно наступить "Задолбался
> ждать" :))
> Сколько времени надо положить на это ?
А мне откуда знать, сколько по твоей задаче ждать положено? :)
← →
Riply © (2007-01-04 08:03) [15]По моей задаче надо убедиться только в том,
что нить приступила к работе (а не висит в процессе создания) и идти дальше.
А она пусть делает све дело :)
← →
Джо © (2007-01-04 08:06) [16]Можно вообще ничего явно не ждать, а выполнять нужные нам действия в отдельной процедуре после старта нити, т.е., в таком роде:
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;
← →
MsGuns © (2007-01-04 08:19) [17]И все-таки я не въехал зачем так хитро чесать пятку ? Ученик ИМХО предложил простое и надежное решение - в основном потоке (модуле) создать некий объект, указатель на который передать потоку. В этом объекте вторичный поток пусть пишет чего хочет, а осн.поток через таймер (например) периодически его (объект) проверяет.
Всего делов-то
← →
Джо © (2007-01-04 08:33) [18]> [17] MsGuns © (04.01.07 08:19)
> И все-таки я не въехал зачем так хитро чесать пятку
Лично я люблю перед сном хитро почесать пятку :)
← →
Loginov Dmitry © (2007-01-04 09:22) [19]> По моей задаче надо убедиться только в том,
Rslt := WaitForSingleObject(hEvent,0);
← →
Riply © (2007-01-04 19:02) [20]>[16] Джо © (04.01.07 08:06)
>Можно вообще ничего явно не ждать
Спасибо. Видимо подобным образом ("подобным" - т.к. формы нет) и поступлю.
>[19] Loginov Dmitry © (04.01.07 09:22)
>Rslt := WaitForSingleObject(hEvent,0);
hEvent - это хэндел события или нити ?
Правда и том, и в другом случае не понимаю: как это может помочь ?
← →
Riply © (2007-01-05 02:21) [21]Может кому - нибудь будет интересно.
Джеффри РИХТЕР
Худшее, что можно сделать.
Если бы синхронизирующих объектов не было, а операционная система
не умела отслеживать особые события, потоку пришлось бы самостоятельно
синхронизировать себя с ними, применяя метод, который я как раз и
собираюсь продемонстрировать. Но поскольку в операционную систему встроена
поддержка синхронизации объектов, никогда не применяйте этот метод.
Суть его в том, что поток синхронизирует себя с завершением какой-либо задачи
в другом потоке, постоянно просматривая значение переменной, доступной обоим
полкам Возьмем пример
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, а не общую переменную. :))
← →
Джо © (2007-01-05 02:27) [22]> Так, что Джо был абсолютно прав (если мы не оспариваем Рихтера)
> ,
> предлагая "хитро чесать пятку" используя Event, а не общую
> переменную. :))
Хитро чесать пятку тоже нужно со знанием. 8^)
← →
Джо © (2007-01-05 06:04) [23]> GetMem (StartInfo,SizeOf(StartInfo));
Ай, какой ляп. Прошу прощения.
← →
Riply © (2007-01-05 06:23) [24]> [23] Джо © (05.01.07 06:04)
Ничего страшного: я сразу увидела эту описку, так что не пострадала :))
← →
TUser © (2007-01-05 14:33) [25]В конструкторе TThread"а создать какой-нибудь мьютекс, а в Execute - освободить его.
← →
Джо © (2007-01-05 15:54) [26]> [25] TUser © (05.01.07 14:33)
> В конструкторе TThread"а создать какой-нибудь мьютекс, а
> в Execute - освободить его.
У нас тутBeginThread
:)
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2007.01.21;
Скачать: [xml.tar.bz2];
Память: 0.53 MB
Время: 0.123 c