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

Вниз

Как правильно блокировать/разблокировать поток?   Найти похожие ветки 

 
DevilDevil ©   (2007-11-07 08:22) [0]

Я не совсем о критических секциях говорю.
Известно, что поток должен простаивать относительно длительное время. Как правильнее реализовать Lock/UnLock для потомка TThread ?

Заранее спасибо


 
Anatoly Podgoretsky ©   (2007-11-07 08:27) [1]

> DevilDevil  (07.11.2007 08:22:00)  [0]

Suspend


 
Сергей М. ©   (2007-11-07 08:35) [2]


> Известно, что поток должен простаивать относительно длительное
> время


Откуда дровишки ? ОБС ?


 
Slym ©   (2007-11-07 08:49) [3]

while not Terminated do
begin
 Event.ResetEvent;
 Event.WaitFor(TimeOut);//или INFINITE
 ...
end;

procedure Thread.Up;
begin
Event.SetEvent;
end;


 
Kolan ©   (2007-11-07 08:51) [4]

WaitForSngleObject еще


 
DevilDevil ©   (2007-11-07 08:52) [5]

я в потоках пока мало разбираюсь...

простенький вопрос: TThread.Execute выполняется только один раз в течение жизни потока ? Тогда как правильнее организовать цикл ?

получиться должон что то типа:

procedure TMyThread.ThreadProc();
begin
  // потоковая процедура, Updater.
end;

procedure TMyThread.Execute();
begin

 while <условие> do
 begin
      if not FLocked then
        ThreadProc();
 end;

end;


 
Kolan ©   (2007-11-07 08:54) [6]

> получиться должон что то типа:

Да.

Классика:
procedure TMyThread.Execute();
begin
while not Terminated do
begin
     if not FLocked then
       ThreadProc();
end;
end;


Только прочти что такое есть Terminated в справке.


 
Сергей М. ©   (2007-11-07 08:58) [7]


> Execute выполняется только один раз в течение жизни потока
> ?


Да.


> как правильнее организовать цикл ?


Критериев "правильности" не существует.
Все зависит от логики, требуемой к реализации в потоке.


 
Slym ©   (2007-11-07 08:58) [8]

uses SyncObjs;
type
TMyThread=class(TThread)
private
 Event:TSimpleEvent;
...

procedure TMyThread.ThreadProc();
begin
 // потоковая процедура, Updater.
end;

procedure TMyThread.Execute();
begin
while not Terminated do
begin
 Event.WaitFor(INFINITE);
 ThreadProc;
end;
end;

procedure Thread.Unlock;
begin
 Event.SetEvent;
end;

procedure Thread.Lock;
begin
 Event.ResetEvent;
end;


 
DevilDevil ©   (2007-11-07 08:59) [9]

хорошо, как правильно изменять флаг FLocked, через криьическую секцию ?
наверняка что-то типа Suspend/Resume навесить, чтобы поток не тратил процессорного времени ?


 
Slym ©   (2007-11-07 09:04) [10]

DevilDevil ©   (07.11.07 8:59) [9]
Suspend/Resume

Это не правильно, поток должен сам остановиться на блокирующей функции (например Event.WaitFor)
Мой вариант чем не нравится?


 
MBo ©   (2007-11-07 09:07) [11]

Опиши задачу


 
DevilDevil ©   (2007-11-07 09:14) [12]

нравится. )
такой вопрос... корректна ли будет работа после:
procedure Thread.Unlock;
begin
Event.SetEvent;
Event.SetEvent;
end;


или

procedure Thread.Lock;
begin
Event.ResetEvent;
Event.ResetEvent;
end;


проще говоря, корректна ли будет выполняться работа при неоднократном вызове Lock() или UnLock() ?

Ну и вопрос напоследок.
Какие проблемы могут меня ожидать при вызове деструктора?
ну не забыть UnLock например, может с критическими секциями проблемы и т.д. ?


 
DevilDevil ©   (2007-11-07 09:20) [13]

Такой ещй маленький вопрос... много ли процессорного времени кушает Event.WaitFor() , есть ли способ экономичней, стоит ли вообще париться ?


 
DevilDevil ©   (2007-11-07 09:42) [14]

Задача - проигрывание звука.
Есть объект - Плеер, который хранит в себе SoundBuffer и Thread.
Поток должен заполнять SoundBuffer данными, но может и не заполнять (простаивать), если Плейер находится в состоянии паузы или стопа. Доступ к буфферу и некоторым данным должен быть синхронизируемым.


 
Kolan ©   (2007-11-07 09:42) [15]

> стоит ли вообще париться

Не стоит.


 
Сергей М. ©   (2007-11-07 09:52) [16]


> DevilDevil ©   (07.11.07 09:42) [14]


Синхронизация доступа к буферу - с пом. крит.секции.

Управление работой потока - с пом. сообщений или системных объектов синхронизации (ивент, мьютекс), можно и крит.секцию прикрутить.

В первом приближении считай, что поток, находящийся в kernel-time, процессорное время не потребляет. Перевод потока в kernel-time осуществляется вызовами ф-ций ожидания - [Msg]WaitForXXXXXX, Wait/GetMessage.


 
DevilDevil ©   (2007-11-07 10:19) [17]

спасибо.

как правильно оформить деструктор? так пойдёт:

procedure TMusicPlayerThread.Execute;
begin
 WHILE TRUE DO
 BEGIN
     Event.WaitFor(INFINITE); //Locked ?
     if Terminated then break;

     try
        FPlayer.BeginCriticalSection();
        FPlayer.OnThreadProc;
     finally
        FPlayer.EndCriticalSection();
     end;

 END;
end;

destructor TMusicPlayerThread.Destroy();
begin
   Terminated := true;
   UnLock();
   Event.Free;

   inherited;
end;


Что мне нужно...
Чтобы при вызове деструктора поток завершился. Но если он уже выполняет OnThreadProc, то подождать завершения этой функции.


 
Kolan ©   (2007-11-07 10:25) [18]

> WHILE TRUE DO

тАК ТОЧНО НЕ ПОЙДЕТ

И потом У тя поток вечно жить будет чтоли?

procedure TMusicPlayerThread.Execute;
begin
FreeOnTerminate := True;
WHILE not Terminated DO
BEGIN
    Event.WaitFor(INFINITE); //Locked ?
    if Terminated then break;

    try
       FPlayer.BeginCriticalSection();
       FPlayer.OnThreadProc;
    finally
       FPlayer.EndCriticalSection();
    end;

END;
end;


 
DevilDevil ©   (2007-11-07 10:42) [19]

1) FreeOnTerminate - хорошее замечание
2) почему While True Do не прокатит, там же есть проверка на Terminated ?
3) в остальном то всё правильно ?


 
Slym ©   (2007-11-07 11:02) [20]

Из прочитаного формализую задачу:
Необходим потокозащищенный объект-буфер с 1 входом (write) и 1 выходом (read), при попытке чтения из пустого буфера читающий поток должен быть остановлен до появления в буфере данных, и пишуший поток должен быть остановлен при попытке писать в заполненный буфер...
для всего этого прекрасно подходит анонимный пайп CreatePipe


 
umbra ©   (2007-11-07 11:20) [21]


> почему While True Do не прокатит, там же есть проверка на
> Terminated ?

прокатит, конечно. просто есть люди, которых бесят циклы вида

while true do .....

но я бы сделал проверку на Terminated в самом начале


 
DevilDevil ©   (2007-11-07 11:42) [22]

> umbra ©   (07.11.07 11:20) [21]

представим ситуацию: на момент деструктора поток был в режиме Lock(), т.е. "Нельзя вызывать функцию OnThreadProc". Мы пишем:
  Terminated := true;
  UnLock();
  Event.Free;


если не ставить условие после WaitFor(), то выполнится функция OnThreadProc, чего делать нельзя!

> Slym ©   (07.11.07 11:02) [20]
ээээ...... слишком много букав и слов сложных О_о?

не совсем понял, что такое объект-буфер с 1 входом (write) и 1 выходом (read)
поток только пишет. но может быть так же в заблокированном состоянии.


 
Slym ©   (2007-11-07 11:55) [23]

DevilDevil ©   (07.11.07 9:42) [14]
Доступ к буфферу и некоторым данным должен быть синхронизируемым

Необходим потокозащищенный объект-буфер с 1 входом (write) и 1 выходом (read)...
Есть как минимум 2 потока: 1 играющий звук - он делает из SoundBuffer чтение read; второй поток заполняет SoundBuffer т.е. делает ему Write
DevilDevil ©   (07.11.07 9:42) [14]
Поток должен заполнять SoundBuffer данными, но может и не заполнять (простаивать),

пишуший поток должен быть остановлен при попытке писать в заполненный буфер...
а играющий поток при попытке чтения из пустого буфера читающий поток должен быть остановлен до появления в буфере данных


 
DevilDevil ©   (2007-11-07 11:57) [24]

и ещё вопрос: процедуры Lock() и UnLock() могут вызываться из обоих потоков; процедуры надо защищать критической секцией ?


 
umbra ©   (2007-11-07 12:04) [25]

а зачем в деструкторе вообще писать Terminated := true;, если он вызовется только после того, как свойству Terminated присвоят значение true?


 
Сергей М. ©   (2007-11-07 12:06) [26]

//обработчик сообщения TM_PLAY
FPlayState := psPlay;
while not PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) do
 DoSomething(..);

//обработчик сообщения TM_PAUSE
 FPlayState := psPause;

//обработчик сообщения TM_STOP
 FPlayState := psStop;

//основной цикл поточной процедуры
while not Terminated and GetMessage(Msg, 0, 0, 0) do
 Dispatch(Msg.message);


 
DevilDevil ©   (2007-11-07 12:58) [27]

> umbra ©   (07.11.07 12:04) [25]

разве ?
а если я из основного потока вызову Thread.Free ?

> Сергей М. ©   (07.11.07 12:06) [26]
имхо кривовато. может через критическую секцию ?


 
Сергей М. ©   (2007-11-07 13:03) [28]


> DevilDevil ©   (07.11.07 12:58) [27]


> может через критическую секцию ?
>


Вот ее как раз и используй в теле DoSomething.

А на этом примере я показал один из вариантов управления потоком.


 
umbra ©   (2007-11-07 13:09) [29]


> а если я из основного потока вызову Thread.Free ?
>

если делать так, то не вижу смысла в строке

FreeOnTerminate := True;

Лучше вызовите Thread.Terminate :)


 
DevilDevil ©   (2007-11-07 13:09) [30]

вобщем, ладно.

я и так многое узнал, полученных знаний скорее всего хватит.

в случае чего ещё раз приду с возгласами "спасите-помогите !!!"

Участникам большое спасибо !


 
DevilDevil   (2007-11-08 00:25) [31]

мда... такой вопрос...

AccessViolation в библиотеке ntdll.dll при выполнении кода:
procedure TMyClass.BeginCriticalSection();
begin
  EnterCriticalSection(FCriticalSection);
end;


В конструкторе TMyClass вызывается ZeroMemory(@FCriticalSection, sizeof(TRTLCriticalSection));


 
Германн ©   (2007-11-08 00:34) [32]

А что ты хотел поиметь вот тут
> @FCriticalSection


 
DevilDevil   (2007-11-08 00:46) [33]

TRTLCriticalSection - структура, которую наверное как то надо инициализировать, которую возможно надо обнулять...


 
Германн ©   (2007-11-08 01:00) [34]


> DevilDevil   (08.11.07 00:46) [33]
>
> TRTLCriticalSection - структура, которую наверное как то
> надо инициализировать, которую возможно надо обнулять...
>
>

В Киеве бузина, а в огороде дядька.
Я тебя спрашивал про то, что по-твоему означает конструкция @FCriticalSection?


 
KilkennyCat ©   (2007-11-08 01:02) [35]


> что по-твоему означает конструкция @FCriticalSection?


собака ф будке, которую пора отремонтировать, либо собака ф бешенстве.


 
DevilDevil   (2007-11-08 01:10) [36]

> Германн ©   (08.11.07 01:00) [34]

я что-то недогоняю, к чему ты клонишь. Взятие указателя конечно.
А как ещё ты вызовешь ZeroMemory ?


 
Германн ©   (2007-11-08 01:31) [37]


> DevilDevil   (08.11.07 01:10) [36]
>
> > Германн ©   (08.11.07 01:00) [34]
>
> я что-то недогоняю, к чему ты клонишь. Взятие указателя
> конечно.
> А как ещё ты вызовешь ZeroMemory ?
>

1. Из справки:
VOID ZeroMemory(

   PVOID Destination,  // address of block to fill with zeros
   DWORD Length  // size, in bytes, of block to fill with zeros  
  );


Parameters

Destination

Points to the starting address of the block of memory to fill with zeros.

И ты решил, что @FCriticalSection даст тебе "адрес начала блока памяти"?

2. Из справки:
The @ operator returns the address of a variable, or of a function, procedure, or method; that is, @ constructs a pointer to its operand. For more information about pointers, see Pointers and pointer types. The following rules apply to @.

If X is a variable, @X returns the address of X.

Перевожу: @ оператор возвращает адрес самой переменной в памяти, а не адрес на который указывает её содержимое.


 
Slym ©   (2007-11-08 06:16) [38]

DevilDevil   (08.11.07 0:25) [31]
ZeroMemory(@FCriticalSection, sizeof(TRTLCriticalSection));

а надо
InitializeCriticalSection(FCriticalSection)


 
Сергей М. ©   (2007-11-08 10:25) [39]


> DevilDevil   (08.11.07 00:25) [31]


Есть готовый класс для работы с крит.секцией - TCliticalSection.
Все что нужно - создать его экз-р и ссылку на него раздать всем заинтересованным в синхронизации потокам.

Вход в секцию - метод Enter, выход - Leave.

И незачем изобретать новый кривой велосипед)


 
DevilDevil ©   (2007-11-08 15:01) [40]

> Slym ©   (08.11.07 06:16) [38]
спасибо, что-то ступил, даже хелп не помотрел.

> Сергей М. ©   (08.11.07 10:25) [39]
тоже спасибо.


 
Loginov Dmitry ©   (2007-11-08 20:49) [41]

> и ещё вопрос: процедуры Lock() и UnLock() могут вызываться
> из обоих потоков; процедуры надо защищать критической секцией
> ?


Тело процедуры ты можещь защитить критической секцией (так наверно и нужно делать). Но в самих процедурах для блокировки / разблакировки потоков использовать мьютексы и критические секции нельзя, т.к. в этом случае пара Lock() / UnLock() всегда должна вызываться в одном и том же потоке. Так что здесь следует использовать Event.


 
Leonid Troyanovsky ©   (2007-11-08 21:32) [42]


> Loginov Dmitry ©   (08.11.07 20:49) [41]

> Тело процедуры ты можещь защитить критической секцией (так
> наверно и нужно делать). Но в самих процедурах для блокировки
> / разблакировки потоков использовать мьютексы и критические
> секции нельзя, т.к. в этом случае пара Lock() / UnLock()
> всегда должна вызываться в одном и том же потоке. Так что
> здесь следует использовать Event.

А хватит Event"а, если тело большое?

--
Regards, LVT.


 
DevilDevil   (2007-11-08 23:12) [43]

недопонял... вот так правильно или нет :

procedure TMusicPlayerThread.Lock();
begin
 try
    FPlayer.BeginCriticalSection();

    Event.ResetEvent();
 finally
    FPlayer.EndCriticalSection();
 end;
end;

procedure TMusicPlayerThread.UnLock();
begin
 try
    FPlayer.BeginCriticalSection();

    Event.SetEvent();
 finally
    FPlayer.EndCriticalSection();
 end;
end;


 
Loginov Dmitry ©   (2007-11-08 23:18) [44]

Функции Lock и UnLock в данном случае - простые и защищать критической секцией здесь нечего.



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

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

Наверх




Память: 0.59 MB
Время: 0.031 c
15-1194023702
Kerk
2007-11-02 20:15
2007.12.02
Вопрос о русском языке


10-1139575478
Shopot
2006-02-10 15:44
2007.12.02
Как в Excel задать ширину столбца?


15-1194263340
KilkennyCat
2007-11-05 14:49
2007.12.02
Сетевой кабель 586-A


4-1179822306
cosinus
2007-05-22 12:25
2007.12.02
Как найти одно из чужих окон по его потомку?


15-1194010490
oldman
2007-11-02 16:34
2007.12.02
Где бы прикупить акций Гугля?