Форум: "Основная";
Текущий архив: 2005.09.18;
Скачать: [xml.tar.bz2];
ВнизКак приостановить поток? Найти похожие ветки
← →
Fay © (2005-08-23 15:43) [40]Reindeer Moss Eater © (23.08.05 15:43) [38]
он может уснуть ГДЕ УГОДНО
← →
Reindeer Moss Eater © (2005-08-23 15:45) [41]Fay, что ты мне хочешь доказать?
Что это не лучший способ?
Так я еще с десяток постов назад сказал, что не стал бы так делать.
← →
Fay © (2005-08-23 15:47) [42]2 Reindeer Moss Eater © (23.08.05 15:45) [41]
Я и не утверждаю, что ты стал бы так делать. Просто говорю - так низя.
← →
Leonid Troyanovsky © (2005-08-23 16:03) [43]
Alexander Panov © (23.08.05 15:43) [39]
>> А если он заснет посредине, скажем, Move?
> Он сам заснет, что-ли?
Это не моя терминология.
> Reindeer Moss Eater © (23.08.05 14:15) [23]
> Вторичным потоком рулит первичный.
> Он ему делает суспенд.
> Список изменяется только когда вторичный поток уснул.
А остановить его могут на любой атомарной операции.
> Кстати, даже четырехбайтовых значений положено InterLocked*
> Это если используется блокировка Interlocked-функциями.
Дык, и надо ее пользовать. Даже для однобайтовых.
--
Regards, LVT.
← →
Внук © (2005-08-23 16:20) [44]>>Alexander Panov © (23.08.05 15:43) [39]
Не смoжешь ты контролировать, когда именно уснет поток. И дело не в том, кто как пишет программы :) Но через Suspend надежной синхронизации не получится.
← →
Alexander Panov © (2005-08-23 16:45) [45]Внук © (23.08.05 16:20) [44]
Не смoжешь ты контролировать, когда именно уснет поток. И дело не в том, кто как пишет программы :) Но через Suspend надежной синхронизации не получится.
А мне и не нужно знать, когда он уснет после моей команды ему. Мне достаточно перед усыплением дождаться, пока поток закончит обработку защищаемых данных, взвести флаг о том, что данные используются в другом потоке, после этого усыпить его. И все. Надежней некуда.
← →
Leonid Troyanovsky © (2005-08-23 16:50) [46]
> Alexander Panov © (23.08.05 16:45) [45]
> Внук © (23.08.05 16:20) [44]
> Не смoжешь ты контролировать, когда именно уснет поток.
> А мне и не нужно знать, когда он уснет после моей команды
> ему. Мне достаточно перед усыплением дождаться, пока поток
> закончит обработку защищаемых данных,
А тогда и не требуется его усыплять (приостанавливать).
Закончил обработку (write) - данные консистентны.
--
Regards, LVT.
← →
Alexander Panov © (2005-08-23 17:13) [47]Leonid Troyanovsky © (23.08.05 16:50) [46]
тогда и не требуется его усыплять (приостанавливать).
Не требуется, если это не нужно.
А если нужно, то никто не мешает это сделать, причем совершенно потокобезопасно относительно совместной работы с данными этого и других потоков.
← →
Leonid Troyanovsky © (2005-08-23 17:25) [48]
> Alexander Panov © (23.08.05 17:13) [47]
>> тогда и не требуется его усыплять (приостанавливать).
> Не требуется, если это не нужно.
> А если нужно, то никто не мешает это сделать, причем совершенно
> потокобезопасно относительно совместной работы с данными
> этого и других потоков.
Дык, зачем тогда потокобезопасно приостанавливать?
Т.е., зачем оно может требоваться для синхронизации,
если оная уже произошла.
--
Regards, LVT.
← →
Alexander Panov © (2005-08-23 17:41) [49]Leonid Troyanovsky © (23.08.05 17:25) [48]
Т.е., зачем оно может требоваться для синхронизации,
если оная уже произошла.
Например, остановить поток для того, чтобы
1. Безопасно работать с другими данными, либо не дать потоку захватить другие данные.
2. Не разрешать потоку холостых циклов.
← →
Leonid Troyanovsky © (2005-08-23 17:48) [50]> Alexander Panov © (23.08.05 17:41) [49]
> Leonid Troyanovsky © (23.08.05 17:25) [48]
> Т.е., зачем оно может требоваться для синхронизации,
> если оная уже произошла.
> Например, остановить поток для того, чтобы
> 1. Безопасно работать с другими данными, либо не дать потоку
> захватить другие данные.
> 2. Не разрешать потоку холостых циклов.
Дык,
1. Эта другая задача синхронизации.
2. Откуда взяться холостым циклам, если поток должен ждать
синхронизирующих событий, т.е., должен спать (уже в терминологии Рихтера).
--
Regards, LVT.
← →
Alexander Panov © (2005-08-23 18:02) [51]Leonid Troyanovsky © (23.08.05 17:48) [50]
2. Откуда взяться холостым циклам, если поток должен ждать
синхронизирующих событий, т.е., должен спать (уже в терминологии Рихтера).
Так весь сыр-бор в ветке из-за того, можно или нет обойтись без объектов синхронизации.
← →
han_malign © (2005-08-23 18:27) [52]>Так весь сыр-бор в ветке из-за того, можно или нет обойтись без объектов синхронизации.
- дык Suspend никаким боком к синхронизации и не относится...
This function is primarily designed for use by debuggers. It is not intended to be used for thread synchronization. Calling SuspendThread on a thread that owns a synchronization object, such as a mutex or critical section, can lead to a deadlock if the calling thread tries to obtain a synchronization object owned by a suspended thread. To avoid this situation, a thread within an application that is not a debugger should signal the other thread to suspend itself. The target thread must be designed to watch for this signal and respond appropriately.
← →
Alexander Panov © (2005-08-23 19:09) [53]han_malign © (23.08.05 18:27) [52]
Хочешь пример, где можно синхронизацию осуществить методами Suspend/Resume?
← →
Fay © (2005-08-23 22:33) [54]2 Alexander Panov © (23.08.05 19:09) [53]
Я, конечно, не han_malign, но давно жду такой пример.
Будьте так добры...
← →
Alexander Panov © (2005-08-24 00:44) [55]Вот совершенно простой пример:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Label1: TLabel;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;
TTest=class(Tthread)
private
FMemo: TMemo;
procedure UpdateMemo;
protected
procedure Execute; override;
public
constructor Create(Memo: TMemo);
end;
var
Form1: TForm1;
Test: Ttest;
isTerminate: Boolean;
implementation
{$R *.dfm}
{ TTest }
constructor TTest.Create(Memo: TMemo);
begin
inherited Create(True);
FreeOnTerminate := True;
FMemo := Memo;
Resume;
end;
procedure TTest.Execute;
begin
while not Terminated do
begin
UpdateMemo;
Sleep(2000);
Suspend;
end;
end;
procedure TTest.UpdateMemo;
begin
FMemo.Lines.Add("Доп. поток: состояние расчетов");
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Test := TTest.Create(Memo1);
isTerminate := False;
with Test do
begin
while not isTerminate do
begin
if Suspended then
begin
Memo1.Lines.Add("Основной поток: работаю с Memo1");
Label1.Caption := "Основной поток: Работаю";
Application.ProcessMessages;
Sleep(1000);
Resume;
end;
while not Suspended do
begin
Label1.Caption := "Основной поток: жду освобождения ресурса";
Application.ProcessMessages;
end;
end;
Label1.Caption := "Поток закончил работу";
Terminate;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
isTerminate := True;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
isTerminate := True;
end;
end.
← →
Alexander Panov © (2005-08-24 00:47) [56]Взять пример можно здесь:
ftp://ftp.almar.net.ru/pub/simplethread/simplethread.zip
← →
Defunct © (2005-08-24 01:07) [57]> Alexander Panov
Пример бесспорно рабочий, но не решает сабжевый вопрос. Всмысле конанду доп потоку на приостановку должен отдавать основной поток. Если можете, подправьте код, (там собсно нечего подправлять, флажек один добавить) было бы интересно и познавательно для всех.
← →
Alexander Panov © (2005-08-24 01:25) [58]Defunct © (24.08.05 1:07) [57]
Напрямую использовать Suspend потоку все равно не получится.
А вот так можно сделать:unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Label1: TLabel;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;
TTest=class(Tthread)
private
FTrySuspend: Boolean;
FMemo: TMemo;
procedure UpdateMemo;
protected
procedure Execute; override;
public
constructor Create(Memo: TMemo);
procedure Suspend;
end;
var
Form1: TForm1;
Test: Ttest;
isTerminate: Boolean;
implementation
{$R *.dfm}
{ TTest }
constructor TTest.Create(Memo: TMemo);
begin
inherited Create(True);
FreeOnTerminate := True;
FMemo := Memo;
FTrySuspend := False;
Resume;
end;
procedure TTest.Execute;
begin
while not Terminated do
begin
UpdateMemo;
Sleep(2000);
if FTrySuspend then
begin
FTrySuspend := False;
Suspended := True;
end;
end;
end;
procedure TTest.Suspend;
begin
FTrySuspend := True;
end;
procedure TTest.UpdateMemo;
begin
FMemo.Lines.Add("Доп. поток: состояние расчетов");
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Test := TTest.Create(Memo1);
isTerminate := False;
while not isTerminate do
begin
Test.Suspend;
while not Test.Suspended do
begin
Label1.Caption := "Основной поток: жду освобождения ресурса";
Application.ProcessMessages;
if isTerminate then Break;
end;
Memo1.Lines.Add("Основной поток: работаю с Memo1");
Label1.Caption := "Основной поток: Работаю";
Application.ProcessMessages;
Sleep(1000);
Test.Resume;
end;
Label1.Caption := "Поток закончил работу";
Test.Terminate;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
IsTerminate := True;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
IsTerminate := True;
end;
end.
← →
Alexander Panov © (2005-08-24 01:27) [59]ftp://ftp.almar.net.ru/pub/simplethread/simplethread1.zip
← →
Defunct © (2005-08-24 01:38) [60]> Alexander Panov
Вполне приличное решение. Даже вероятно в некоторых случаях лучше чем крит. секция.
Только, я бы добавил еще следующее изменение, чтобы после вызова suspend управляющий поток гарантировано мог работать с данными остановленного потока без лишних проверок:procedure TTest.Suspend;
begin
fTrySuspend := True;
while fTrySuspend do
begin
sleep(10);
Application.ProcessMessages
end
end;
← →
Внук © (2005-08-24 08:48) [61]>>Alexander Panov © (23.08.05 16:45) [45]
>>Alexander Panov © (24.08.05 01:25) [58]
Угу, это гарантирует безопасный доступ к данным, но во время работы второго потока первый может еще не перейти в состояние приостановки, то есть ему все еще будет выделяться процессорное время. Да и приостанавливать его, как уже отмечали, в этом случае необязательно. Таким образом, мы говорим об одном и том же, только я не считаю возможным в этом случае использовать термин "синхронизация" :)
← →
Игорь Шевченко © (2005-08-24 09:47) [62]Иван Кулибин в гробу от зависти переворачивается.
← →
Alexander Panov © (2005-08-24 10:01) [63]Игорь Шевченко © (24.08.05 9:47) [62]
"Голь на выдумки хитра" ;)
← →
Fay © (2005-08-24 14:06) [64]2 Alexander Panov © (24.08.05 1:27) [59]
Во-первых...
Посмотрите загрузку процессора.
← →
Alexander Panov © (2005-08-24 14:07) [65]Fay © (24.08.05 14:06) [64]
Во-первых...
Посмотрите загрузку процессора.
А что, были разговоры про загрузку процессора?
← →
Fay © (2005-08-24 16:47) [66]2 Alexander Panov © (24.08.05 14:07) [65]
Ошибку можно ждать долго.
Я несколько модифицировал приведённый код.
Если модификация не кажется правомерной - скажите.
Если во время работы программы перетащить форму - будет галюн.unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
PPInteger = ^PInteger;
TForm1 = class(TForm)
Button1 : TButton;
Label1 : TLabel;
Button2 : TButton;
procedure Button1Click(Sender : TObject);
procedure Button2Click(Sender : TObject);
procedure FormClose(Sender : TObject; var Action : TCloseAction);
end;
TTest = class(Tthread)
private
FTrySuspend : Boolean;
FP : PPInteger;
procedure UpdateMemo;
protected
procedure Execute; override;
public
constructor Create(p : PPInteger); reintroduce;
procedure Suspend;
end;
var
Form1 : TForm1;
Test : Ttest;
isTerminate : Boolean;
implementation
{$R *.dfm}
{ TTest }
constructor TTest.Create(p : PPInteger);
begin
inherited Create(True);
FreeOnTerminate := True;
FP := p;
FTrySuspend := False;
Resume;
end;
procedure TTest.Execute;
begin
while not Terminated do
begin
UpdateMemo;
if FTrySuspend then
begin
FTrySuspend := False;
// Sleep(100);
Suspended := True;
end;
end;
end;
procedure TTest.Suspend;
begin
FTrySuspend := True;
end;
procedure TTest.UpdateMemo;
var
p : PInteger;
begin
p := FP^;
FP^ := nil;
Sleep(555);
FP^ := p;
end;
procedure TForm1.Button1Click(Sender : TObject);
var
n : Integer;
p : PInteger;
begin
n := 0;
p := @n;
Test := TTest.Create(@p);
isTerminate := False;
while not isTerminate do
begin
Test.Suspend;
while not Test.Suspended do
begin
Label1.Caption := "Основной поток: жду освобождения ресурса";
Application.ProcessMessages;
// Тут выяснилось, что кнопку Button2 нажали
// if isTerminate then
Break;
end;
Label1.Caption := "Основной поток: Работаю";
Application.ProcessMessages;
Inc(p^);
Sleep(777);
Inc(p^);
Test.Resume;
end;
Label1.Caption := "Поток закончил работу";
Test.Terminate;
end;
procedure TForm1.Button2Click(Sender : TObject);
begin
IsTerminate := True;
end;
procedure TForm1.FormClose(Sender : TObject; var Action : TCloseAction);
begin
IsTerminate := True;
end;
end.
← →
Fay © (2005-08-24 17:04) [67]Можно несколько упростить.
procedure TTest.UpdateMemo;
var
p : PInteger;
begin
p := FP^;
FP^ := nil;
Application.ProcessMessages;
FP^ := p;
end;
procedure TForm1.Button1Click(Sender : TObject);
var
n : Integer;
p : PInteger;
begin
n := 0;
p := @n;
Test := TTest.Create(@p);
isTerminate := False;
while not isTerminate do
begin
Test.Suspend;
while not Test.Suspended do
begin
Label1.Caption := "Основной поток: жду освобождения ресурса";
Application.ProcessMessages;
// Тут выяснилось, что кнопку Button2 нажали
// if isTerminate then
if n > 10 then
Break;
end;
Label1.Caption := "Основной поток: Работаю";
Application.ProcessMessages;
Inc(p^);
Test.Resume;
end;
Label1.Caption := "Поток закончил работу";
Test.Terminate;
end;
← →
Fay © (2005-08-24 17:59) [68]2 Alexander Panov
Ау! Вы где? Ваш, IMO, пример кривой!
← →
Alexander Panov © (2005-08-24 18:25) [69]Fay © (24.08.05 16:47) [66]
Если во время работы программы перетащить форму - будет галюн.
А кто сказал, что пример на это расчитан?
Замени TMemo на TStringList - ошибка исчезнет.
← →
Fay © (2005-08-24 18:34) [70]2 Alexander Panov © (24.08.05 18:25) [69]
Ничего не нужно таскать. Просто надо взять [67]
← →
Fay © (2005-08-24 18:45) [71]Alexander Panov © (24.08.05 18:25) [69]
... да и нет там никакого Memo ...
← →
Defunct © (2005-08-24 18:58) [72]> Fay
А такой вариант не глючит, и процессорное время не хавает.type
TThreadEx = class(TThread)
private
fMemo : TMemo;
fTrySuspend : boolean;
procedure Execute;override;
public
procedure Suspend;
constructor Create(AMemo : TMemo);
end;
constructor TThreadEx.Create;
begin
if not Assigned( AMemo ) then
raise Exception.Create("не насилуй");
fMemo := AMemo;
inherited Create( True );
FreeOnTerminate := True;
fTrySuspend := false;
resume;
end;
procedure TThreadEx.Suspend;
begin
fTrySuspend := True;
while not fTrySuspend do
begin
sleep(0);
//Application.ProcessMessages;
end;
end;
procedure TThreadEx.Execute;
begin
while not Terminated do
begin
fMemo.Lines.Text := "работает доп поток";
if fTrySuspend then
begin
fTrySuspend := False;
fMemo.Lines.Text := "доп поток остановлен по требованию";
inherited Suspend;
end;
end;
end;
var
ThreadEx : TThreadEx = nil;
procedure TForm1.Button1Click(Sender: TObject);
begin
ThreadEx := TThreadEx.Create( Memo1 );
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if Assigned( ThreadEx ) then
begin
ThreadEx.Suspend;
Memo1.Lines.Text := "Поток остановлен";
end;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
if Assigned( ThreadEx ) then
begin
ThreadEx.Resume;
end;
end;
← →
Fay © (2005-08-24 19:06) [73]2 Defunct © (24.08.05 18:58) [72]
Первое впечатление : совершенно не понятно, что демонстрирует пример. Защиту чего от чего?
Можно полный код?
P.S.
Проверкиif Assigned( ThreadEx )
не надёжны, т.к. FreeOnTerminate := True;
← →
Fay © (2005-08-24 19:09) [74]Fay © (24.08.05 19:06) [73]
Так же не вижу (я, конечно, ещё посмотрю внимательно), гдеThreadEx := nil
. Без этогоif Assigned(ThreadEx)
не имеет смысла.
← →
Defunct © (2005-08-24 19:27) [75]Fay © (24.08.05 19:06) [73]
> Защиту чего от чего?
Пофантазируйте. Поставьте
ThreadEx.Suspend;
< меняем поля ThreadEx >
ThreadEx.Resume;
← →
Defunct © (2005-08-24 19:37) [76]> Fay
> Проверки if Assigned( ThreadEx ) не надёжны, т.к. FreeOnTerminate := True;
Я знаю, они там ни на что не влияют, более того в этом куске кода не предусмотрено завершения потока. Т.к. оно и не надо для демострации синхронизации.
← →
Fay © (2005-08-24 19:57) [77]2 Defunct © (24.08.05 19:37) [76]
Я тут немного пофантазировал. Попробуйте 8).unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
PPInteger = ^PInteger;
TForm1 = class(TForm)
Button1 : TButton;
Label1 : TLabel;
Button2 : TButton;
Button3 : TButton;
procedure Button1Click(Sender : TObject);
procedure Button2Click(Sender : TObject);
procedure Button3Click(Sender : TObject);
end;
TThreadEx = class(TThread)
private
FTrySuspend : Boolean;
FP : PPInteger;
protected
procedure Execute; override;
public
constructor Create(p : PPInteger); reintroduce;
procedure Suspend;
end;
var
Form1 : TForm1;
implementation
{$R *.dfm}
var
ThreadEx : TThreadEx = nil;
constructor TThreadEx.Create(p : PPInteger);
begin
inherited Create(True);
if not Assigned(p^) then
raise Exception.Create("не насилуй");
FP := p;
FreeOnTerminate := True;
fTrySuspend := false;
Resume;
end;
procedure TThreadEx.Execute;
procedure DoIt;
var
p : PInteger;
begin
p := FP^;
FP^ := nil;
Sleep(0); // Потоку ничто не мешает переключиться именно здесь
FP^ := p;
end;
begin
while not Terminated do
begin
DoIt;
if fTrySuspend then
begin
fTrySuspend := False;
inherited Suspend;
end;
end;
end;
procedure TThreadEx.Suspend;
begin
FTrySuspend := True;
while not fTrySuspend do
Sleep(0);
end;
procedure TForm1.Button1Click(Sender : TObject);
var
n : Integer;
p : PInteger;
begin
n := 0;
p := @n;
ThreadEx := TThreadEx.Create(@p);
repeat
ThreadEx.Suspend;
Inc(p^);
Caption := IntToStr(p^);
Application.ProcessMessages;
ThreadEx.Resume;
until p^ >= 999;
ThreadEx := nil;
end;
procedure TForm1.Button2Click(Sender : TObject);
begin
if Assigned(ThreadEx) then
ThreadEx.Resume;
end;
procedure TForm1.Button3Click(Sender : TObject);
begin
if Assigned(ThreadEx) then
ThreadEx.Suspend;
end;
end.
← →
Defunct © (2005-08-24 21:03) [78]Fay © (24.08.05 19:57) [77]
По меньшей мере вы делаете преднамерено небезопастный код, игнорируете синхронизацию - обращаетесь к незащищенной переменной в until, т.к. обращения к P^ безопастны только между Suspend<->Resume.
Знаете, можно и с крит. секцией сделать такую ошибку.procedure TThreadEx.Execute;
...
CS.Acquire;
try
DoIt;
finally
CS.Release
end;
...
end;ThreadEx := TThreadEx.Create(@p);
repeat
ThreadEx.Suspend;
CS.Acquire;
try <--- ЗДЕСЬ ОБРАЩЕНИЕ К P^ БЕЗОПАСТНО
Inc(p^);
Caption := IntToStr(p^);
finally
CS.Release;
end;
Application.ProcessMessages;
ThreadEx.Resume;
until p^ >= 999; <--- ЗДЕСЬ ТОЖЕ ТРЕБУЕТСЯ ЗАЩИТА
<--- ЛИБО БУДЬТЕ ДОБРЫ СКОПИРУЙТЕ ЗНАЧЕНИЕ,
<--- НА ТОМ УЧАСТКЕ КОДА, ГДЕ ОБРАЩЕНИЕ
<--- К P^ БЫЛО ЗАЩИЩЕНО.
ThreadEx := nil;
← →
Fay © (2005-08-24 21:14) [79]2 Defunct © (24.08.05 21:03) [78]
until n >= 999
← →
Fay © (2005-08-24 21:17) [80]Defunct © (24.08.05 21:03) [78]
Со всеми бывает. У меня ещё других дел хватает, проглядел.
Пусть будет так 8)var
n, i : Integer;
p : PInteger;
begin
n := 0;
p := @n;
ThreadEx := TThreadEx.Create(@p);
repeat
ThreadEx.Suspend;
Inc(p^);
Caption := IntToStr(p^);
Application.ProcessMessages;
i := n;
ThreadEx.Resume;
until i >= 999;
ThreadEx := nil;
Страницы: 1 2 3 4 вся ветка
Форум: "Основная";
Текущий архив: 2005.09.18;
Скачать: [xml.tar.bz2];
Память: 0.65 MB
Время: 0.016 c