Multithreading 为什么一根线有时会挂在等待?
在我的应用程序中,我使用基于线程的任务。它们工作正常,但有时会挂起应用程序。在下面的代码中,Multithreading 为什么一根线有时会挂在等待?,multithreading,delphi,Multithreading,Delphi,在我的应用程序中,我使用基于线程的任务。它们工作正常,但有时会挂起应用程序。在下面的代码中,过程停止有时挂起在等待过程中。这是因为FStopEvent.SetEvent似乎并不总是起作用 在正常执行期间,线程进入Execute过程,执行OnWork过程,直到调用Stop(设置终止),然后执行一些后处理,然后退出。这是等待退出的信号,每个人都很高兴。在我的使用中,发生这种情况是因为任务被销毁。在这种情况下,调用基类的析构函数,它调用Stop 在某些情况下,这是行不通的Execute输入正确,执行O
过程停止
有时挂起在等待
过程中。这是因为FStopEvent.SetEvent
似乎并不总是起作用
在正常执行期间,线程进入Execute
过程,执行OnWork
过程,直到调用Stop
(设置终止
),然后执行一些后处理,然后退出。这是等待退出的信号,每个人都很高兴。在我的使用中,发生这种情况是因为任务被销毁。在这种情况下,调用基类的析构函数,它调用Stop
在某些情况下,这是行不通的Execute
输入正确,执行OnWork
过程调用正常,但对FStopEvent.SetEvent
没有反应。没有崩溃(除了未执行之外,处的语句),只是什么都没有。由于WaitFor未返回,程序挂起。通过调试DCU,我可以追溯到单元类中的WaitFor
,其中程序挂起在WaitForSingleObject(H[0],无穷大)代码>。OnWork
回调是相同的
工作前和工作后的程序均为零MaxLoops=-1
和FreeOnTerminate=False
。我很绝望,希望有人能找到出路
编辑1:我所说的WaitFor
发生在下面列出的类TEvent\u-Driven\u任务中。因为这个类是从classTSimple_Task
派生的,所以为了完整性,我添加了这个类
编辑2:应用程序。ProcessMessages
已从TSimple_任务中删除。停止
,因为Marjan Venema指出这可能会导致问题。结果是相同的(程序挂起在WaitFor
)
单元并行事件任务;
接口
使用窗体、窗口、类、SysUtils、SyncObjs、,
并行简单任务;
类型
TEvent\u驱动的任务=类(TSimple\u任务)
私有的
FWorkEvent:TEvent;//事件,表示应完成某些工作
公众的
构造函数Create(work:TNotifyEvent;CreateSuspended:boolean=False;
max:Int32=1;
之前:TNotifyEvent=nil;之后:TNotifyEvent=nil;
终止:布尔值=True;任务:整数=1);推翻
毁灭者毁灭;推翻
程序激活(工作:TNotifyEvent=nil);
程序执行;推翻
程序停止;推翻
程序发布;推翻
完类别:TEvent_驱动的_任务//
实施
构造函数TEvent_驱动的任务。创建
(
work:TNotifyEvent;//在执行循环中要做的工作
CreateSuspended:boolean=False;//False=start now,True=use start
max:Int32=1;//执行循环的最大循环数,负=无限循环
before:TNotifyEvent=nil;//在执行循环之前调用
after:TNotifyEvent=nil;//在执行循环之后调用
terminate:boolean=True;//如果为True,则在终止时释放任务
任务:整数=1//任务ID
);
开始
继承的创建(工作、创建挂起、最大、之前、之后、终止、任务);
FWorkEvent:=TEvent.Create(nil,False,False,”);
完创造//
析构函数TEvent_Driven_Task.Destroy;
开始
继承性破坏;
完毁灭//
程序TEvent_Driven_Task.Activate(工作:TNotifyEvent=nil);
开始
如果分配(工作),则在职:=工作;
FWorkEvent.SetEvent;
完激活//
//Execute调用while循环中的OnWork事件处理程序。
//在进入循环之前,执行OnBeforeWork,after:OnAfterWork。
程序TEvent_Driven_Task.Execute;
变量2:TWOHandleArray;
pwo:pwohandlearay;
雷特:德沃德;
开始
pwo:=@2;
pwo[0]:=FWorkEvent.Handle;
pwo[1]:=FStopEvent.Handle;
名称线程为debugging(AnsiString(FTaskName));
FLoop:=0;
尝试
如果分配(上班前),则上班前(自己);
而(未终止)和(循环最大循环)则
开始
FLoop:=FLoop+1;
ret:=WaitForMultipleObjects(2,pwo,FALSE,无限);
如果ret=WAIT_失败,则中断;
案例检索
等待对象0+0:如果已分配(工作),则为工作(自身);
等待对象0+1:终止;
完案例
完虽然
如果分配(在下班后),则在下班后(自己);
//拦截并忽略中断,但保留消息
除了
关于e:exception do FError_Mess:=e.Message;
完试试……除了
完执行//
程序TEvent_Driven_Task.Stop;
开始
终止
FStopEvent.SetEvent;
如果不是自由终止
然后等待;
完停止//
程序TEvent_驱动_Task.Release;
开始
遗传释放;
免费;
完释放//
完单元:并行任务//
================基类=======================
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 //
单元并行简单任务;
接口
使用Windows、类、SysUtils、SyncObjs和窗体;
类型
t简单任务=类(TThread)
受保护的
FStopEvent:TEvent;//表示线程必须终止的事件,由Stop设置
fta:整数;//任务序列号
FTaskName:string;//任务名称
FLoop:integer;//指示已处理工作的次数
FMax_循环:整数;//最大迭代次数
FError_Mess:string;//如果发生异常,则显示错误消息,否则为空
FOnBeforeWork:TNotifyEvent;//在进入线程循环之前调用的事件
FOnWork:TNotifyEvent;//事件在执行循环中被标度
后续工作:TNotifyEvent;//在t之后调用的事件
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 //