Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Ожидание начала работы нити.


Страницы:   1 2

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);
Нужно дождаться не завершения нити (она может работать и до потопа),
а "начала выполнения кода в ее теле"


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо