내 응용 프로그램에서 스레드 기반 작업을 사용합니다. 그들은 잘 작동하지만 때로는 응용 프로그램을 걸어. 아래의 코드에서 procedure Stop
은 WaitFor
절차에 때때로 응답하지 않습니다. FStopEvent.SetEvent
이 항상 작동하는 것으로 보이지 않기 때문입니다. 스레드가 Execute
절차 입사 정상 실행되는 동안왜 스레드가 waitfor에서 정지합니까?
후 다음 종료 후 처리를 수행하고, (Terminated
설정) Stop
가 호출 될 때까지 OnWork
절차를 실행한다. 그것은 WaitFor
에 대한 신호이며 모두가 행복합니다. 내 사용에서는이 작업이 파괴되기 때문에 발생합니다. 이 경우 Stop
을 호출하는 기본 클래스의 소멸자가 호출됩니다.
경우에 따라 작동하지 않는 경우도 있습니다. Execute
이 올바르게 입력되면 OnWork
프로 시저 호출은 ok로 실행되지만 FStopEvent.SetEvent
에는 반응이 없습니다. 충돌이 발생하지 않았습니다 (except
에있는 진술은 실행되지 않습니다). WaitFor가 반환되지 않기 때문에 프로그램이 중단됩니다. 디버그 DCU를 사용하면 프로그램이 WaitForSingleObject(H[0], INFINITE);
에 멈추는 Classes
단위의 WaitFor
으로 다시 추적 할 수 있습니다. OnWork
콜백은 동일합니다.
OnBeforeWork 및 OnAfterWork 프로시 저는 nil입니다. MaxLoops = -1
및 FreeOnTerminate = False
. 나는 절망적이다. 누군가가 빠져 나갈 수 있기를 바란다.
편집 1 :WaitFor
나는 아래 클래스 TEvent_Driven_Task
에 대해 이야기하고 있습니다. 이 클래스는 클래스 TSimple_Task
에서 파생되었으므로이 클래스를 추가하여 완성되었습니다.
편집 2 : 마르 얀 Venema가이 문제를 일으킬 수 있다는 언급으로Application.ProcessMessages
은 TSimple_Task.Stop
에서 제거되었습니다. 결과는 동일합니다 (프로그램은 WaitFor
에 있습니다).
unit Parallel_Event_Task;
interface
uses Forms, Windows, Classes, SysUtils, SyncObjs,
Parallel_Simple_Task;
type
TEvent_Driven_Task = class (TSimple_Task)
private
FWorkEvent: TEvent; // Event signalling that some work should be done
public
constructor Create (work: TNotifyEvent; CreateSuspended: boolean = False;
max: Int32 = 1;
before: TNotifyEvent = nil; after: TNotifyEvent = nil;
terminate: boolean = True; task: integer = 1); override;
destructor Destroy; override;
procedure Activate (work: TNotifyEvent = nil);
procedure Execute; override;
procedure Stop; override;
procedure Release; override;
end; // Class: TEvent_Driven_Task //
implementation
constructor TEvent_Driven_Task.Create
(
work: TNotifyEvent; // Work to do in Execute loop
CreateSuspended: boolean = False; // False = start now, True = use Start
max: Int32 = 1; // Max loops of Execute loop, negative = infinite loop
before: TNotifyEvent = nil;// Called before Execute loop
after: TNotifyEvent = nil; // Called after Execute loop
terminate: boolean = True; // When true free the task on termination
task: integer = 1 // Task ID
);
begin
inherited Create (work, CreateSuspended, max, before, after, terminate, task);
FWorkEvent := TEvent.Create (nil, False, False, '');
end; // Create //
Destructor TEvent_Driven_Task.Destroy;
begin
inherited Destroy;
end; // Destroy //
procedure TEvent_Driven_Task.Activate (work: TNotifyEvent = nil);
begin
if Assigned (work) then OnWork := work;
FWorkEvent.SetEvent;
end; // Activate //
// Execute calls event handler OnWork in a while loop.
// Before the loop is entered, OnBeforeWork is executed, after: OnAfterWork.
procedure TEvent_Driven_Task.Execute;
var two: TWOHandleArray;
pwo: PWOHandleArray;
ret: DWORD;
begin
pwo := @two;
pwo [0] := FWorkEvent.Handle;
pwo [1] := FStopEvent.Handle;
NameThreadForDebugging (AnsiString (FTaskName));
FLoop := 0;
try
if Assigned (OnBeforeWork) then OnBeforeWork (Self);
while (not Terminated) and (Loop <> Max_Loops) do
begin
FLoop := FLoop + 1;
ret := WaitForMultipleObjects (2, pwo, FALSE, INFINITE);
if ret = WAIT_FAILED then Break;
case ret of
WAIT_OBJECT_0 + 0: if Assigned (OnWork) then OnWork (Self);
WAIT_OBJECT_0 + 1: Terminate;
end; // case
end; // while
if Assigned (OnAfterWork) then OnAfterWork (Self);
// Intercept and ignore the interruption but keep the message
except
on e: exception do FError_Mess := e.Message;
end; // try..except
end; // Execute //
procedure TEvent_Driven_Task.Stop;
begin
Terminate;
FStopEvent.SetEvent;
if not FreeOnTerminate
then WaitFor;
end; // Stop //
procedure TEvent_Driven_Task.Release;
begin
inherited Release;
FWorkEvent.Free;
end; // Release //
end. // Unit: Parallel_Simple_Task //
============= 기본 클래스 =======================
unit Parallel_Simple_Task;
interface
uses Windows, Classes, SysUtils, SyncObjs, Forms;
type
TSimple_Task = class (TThread)
protected
FStopEvent: TEvent; // Event signalling that the thread has to terminate, set by Stop
FTaskID: integer; // Task sequence number
FTaskName: string; // Task name
FLoop: integer; // Indicates number of times Work has been processed
FMax_Loops: integer; // Maximum # of iterations
FError_Mess: string; // Error message if an exception occurred, else empty
FOnBeforeWork: TNotifyEvent; // Event to be called just before thread loop is entered
FOnWork: TNotifyEvent; // Event caled in Execute loop
FOnAfterWork: TNotifyEvent; // Event to be called just after thread loop is finished
procedure set_name (value: string);
public
constructor Create (work: TNotifyEvent; CreateSuspended: boolean = False; max: Int32 = 1;
before: TNotifyEvent = nil; after: TNotifyEvent = nil;
terminate: boolean = True; task: integer = 1); reintroduce; virtual;
destructor Destroy; override;
procedure Execute; override;
procedure Stop; virtual;
procedure Release; virtual;
property TaskID: integer read FTaskID;
property TaskName: string read FTaskName write set_name;
property Loop: integer read FLoop;
property Max_Loops: integer read FMax_Loops write FMax_Loops;
property OnBeforeWork: TNotifyEvent read FOnBeforeWork write FOnBeforeWork;
property OnWork: TNotifyEvent read FOnWork write FOnWork;
property OnAfterWork: TNotifyEvent read FOnAfterWork write FOnAfterWork;
end; // Class: TSimple_Task //
implementation
constructor TSimple_Task.Create
(
work: TNotifyEvent; // Work to do in Execute loop
CreateSuspended: boolean = False; // False = start now, True = use Start
max: Int32 = 1; // Max loops of Execute loop
before: TNotifyEvent = nil;// Called before Execute loop
after: TNotifyEvent = nil; // Called after Execute loop
terminate: boolean = True; // When true free the task on termination
task: integer = 1 // Task ID
);
begin
// The thread will only be started when this constructor ends.
inherited Create (CreateSuspended);
FStopEvent := TEvent.Create (nil, True, False, '');
FError_Mess := '';
FTaskID := task;
FTaskName := '';
Max_Loops := max;
OnBeforeWork := before;
OnWork := work;
OnAfterWork := after;
FreeOnTerminate := terminate;
end; // Create //
destructor TSimple_Task.Destroy;
begin
Stop;
Release;
inherited Destroy;
end; // Destroy //
// Execute calls event handler OnWork in a while loop.
// Before the loop is entered, OnBeforeWork is executed, after: OnAfterWork.
procedure TSimple_Task.Execute;
var ret: DWORD;
begin
try
NameThreadForDebugging (AnsiString (FTaskName));
FLoop := 0;
if Assigned (OnBeforeWork) then OnBeforeWork (Self);
while (not Terminated) and (FLoop <> Max_Loops) do
begin
ret := WaitForSingleObject (FStopEvent.Handle, 0);
if ret = WAIT_OBJECT_0 then
begin
Terminate;
end else
begin
if Assigned (OnWork) then OnWork (Self);
FLoop := FLoop + 1;
end; // if
end; // while
if not Terminated and Assigned (OnAfterWork) then OnAfterWork (Self);
// Intercept and ignore the interruption but keep the message
except
on e: exception do FError_Mess := e.Message;
end; // try..except
end; // Execute //
procedure TSimple_Task.Stop;
begin
Terminate;
FStopEvent.SetEvent;
if not FreeOnTerminate
then WaitFor;
end; // Stop //
procedure TSimple_Task.Release;
begin
FStopEvent.Free;
end; // Release //
procedure TSimple_Task.set_name (value: string);
begin
FTaskName := value;
end; // set_name //
end. // Unit: Parallel_Simple_Task //
실행중인 Execute 메서드는 무엇입니까? 너는 두 명을 올렸다. 어떤거야? 차단 된 스레드는 무엇입니까? 디버거가 당신에게 무엇을 말합니까? 현대 Delphis의 스레드 창은 차단하고있는 내용을 알려줍니다. –
TEvent_Driven_Task에있는 스레드입니다. – Arnold
스레드 상태를 의미하는지 디버거가 알려주지 않습니다. 모든 스레드가 중지되고 모든 상태를 알 수 없으며 대기 체인이 없습니다. 이는 실행 중 상태이기도하지만 OnWork 루틴이 많은 실행 시간을 필요로하지 않기 때문에 발생할 수 있습니다. 이 스레드는 FWorkEvent가 트리거되기를 기다리고 있습니다. – Arnold