-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathPkg.Json.ThreadingEx.pas
132 lines (111 loc) · 3.81 KB
/
Pkg.Json.ThreadingEx.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
unit Pkg.Json.ThreadingEx;
interface
uses
SysUtils,
Threading;
type
TAction<T> = reference to procedure(const arg: T);
TTaskContinuationOptions = (NotOnCompleted, NotOnFaulted, NotOnCanceled, OnlyOnCompleted, OnlyOnFaulted, OnlyOnCanceled);
ITaskEx = interface(ITask)
['{3AE1A614-27AA-4B5A-BC50-42483650E20D}']
function GetExceptObj: Exception;
function GetStatus: TTaskStatus;
function ContinueWith(const continuationAction: TAction<ITaskEx>; continuationOptions: TTaskContinuationOptions): ITaskEx;
function ContinueWithInMainThread(const continuationAction: TAction<ITaskEx>; continuationOptions: TTaskContinuationOptions): ITaskEx;
property ExceptObj: Exception read GetExceptObj;
property Status: TTaskStatus read GetStatus;
end;
TTaskEx = class(TTask, ITaskEx)
private
fExceptObj: Exception;
function GetExceptObj: Exception;
function InternalContinueWith(const continuationAction: TAction<ITaskEx>; continuationOptions: TTaskContinuationOptions; aMainThread: boolean): ITaskEx;
protected
function ContinueWith(const continuationAction: TAction<ITaskEx>; continuationOptions: TTaskContinuationOptions): ITaskEx;
function ContinueWithInMainThread(const continuationAction: TAction<ITaskEx>; continuationOptions: TTaskContinuationOptions): ITaskEx;
public
destructor Destroy; override;
class function Run(const action: TProc): ITaskEx; static;
class function QueueMainThread(aDelay: Integer; const action: TProc): ITaskEx; overload;
end;
implementation
uses
Classes;
{ TTaskEx }
function TTaskEx.ContinueWith(const continuationAction: TAction<ITaskEx>; continuationOptions: TTaskContinuationOptions): ITaskEx;
begin
Result := InternalContinueWith(continuationAction, continuationOptions, false);
end;
function TTaskEx.ContinueWithInMainThread(const continuationAction: TAction<ITaskEx>; continuationOptions: TTaskContinuationOptions): ITaskEx;
begin
Result := InternalContinueWith(continuationAction, continuationOptions, true);
end;
destructor TTaskEx.Destroy;
begin
fExceptObj.Free;
inherited;
end;
function TTaskEx.GetExceptObj: Exception;
begin
Result := fExceptObj;
end;
function TTaskEx.InternalContinueWith(const continuationAction: TAction<ITaskEx>; continuationOptions: TTaskContinuationOptions; aMainThread: boolean): ITaskEx;
begin
Result := TTaskEx.Run(
procedure
var
task: ITaskEx;
doContinue: boolean;
begin
task := Self;
if not IsComplete then
DoneEvent.WaitFor;
fExceptObj := GetExceptionObject;
case continuationOptions of
NotOnCompleted:
doContinue := GetStatus <> TTaskStatus.Completed;
NotOnFaulted:
doContinue := GetStatus <> TTaskStatus.Exception;
NotOnCanceled:
doContinue := GetStatus <> TTaskStatus.Canceled;
OnlyOnCompleted:
doContinue := GetStatus = TTaskStatus.Completed;
OnlyOnFaulted:
doContinue := GetStatus = TTaskStatus.Exception;
OnlyOnCanceled:
doContinue := GetStatus = TTaskStatus.Canceled;
else
doContinue := false;
end;
if doContinue then
if aMainThread then
TThread.Synchronize(nil,
procedure
begin
continuationAction(task);
end)
else
continuationAction(task);
end);
end;
class function TTaskEx.QueueMainThread(aDelay: Integer; const action: TProc): ITaskEx;
begin
Result := Run(
procedure
begin
TThread.Sleep(aDelay);
TThread.Queue(nil,
procedure
begin
action;
end);
end);
end;
class function TTaskEx.Run(const action: TProc): ITaskEx;
var
task: TTaskEx;
begin
task := TTaskEx.Create(nil, TNotifyEvent(nil), action, TThreadPool.Default, nil);
Result := task.Start as ITaskEx;
end;
end.