///////////// IbcTaskThread / IbcSleepingThread ~ svc_taskthread.pas ////////////////
{ task definitions we can handle "In Our Sleep" :o) }
{ TTaskEvent = procedure(Sender: TObject) of object; we call this with provided data }
TTaskEvent = TNotifyEvent;
{ extended TTaskEvent, sig: TTaskEventEx = procedure(anObj: TObject;aPtr: pointer) of object; }
TTaskEventEx = procedure(anObj: TObject;aPtr: pointer) of object;
{ TTaskFunc = function(Parameter: pointer): ptrint; we call this with provided data }
TTaskFunc = TThreadFunc;
{ TTaskProc = procedure(aParam: pointer); or we also call this with provided data }
TTaskProc = procedure(aParam: pointer);
{ designated error }
ETaskThreadError = class(Exception);
{ TTaskThread is our base worker-bee, purely abstract here, will get overridden }
TTaskThread = class(TThread)
protected
fCaller: ptrint; { owner handle }
fID: ptrint; { own id, given to us by the controller }
fSync: IReadWriteSync; { our internal locking object }
fTaskEvent: TTaskEvent; ///=^
fTaskEventEx: TTaskEventEx; ///=^
fTaskFunc: TTaskFunc; ///=^
fTaskProc: TTaskProc; ///=^
function get_ID: ptrint; virtual; abstract;
function get_Sync: IReadWriteSync; virtual; abstract;
function get_TaskEvent: TTaskEvent; virtual; abstract;
function get_TaskEventEx: TTaskEventEx; virtual; abstract;
function get_TaskFunc: TTaskFunc; virtual; abstract;
function get_TaskProc: TTaskProc; virtual; abstract;
procedure set_TaskEvent(aValue: TTaskEvent); virtual; abstract;
procedure set_TaskEventEx(aValue: TTaskEventEx); virtual; abstract;
procedure set_TaskFunc(aValue: TTaskFunc); virtual; abstract;
procedure set_TaskProc(aValue: TTaskProc); virtual; abstract;
public
property ID: ptrint read get_ID; { unprotected access }
property Sync: IReadWriteSync read get_Sync; { protection }
property TaskEvent: TTaskEvent read get_TaskEvent write set_TaskEvent; { protected access }
property TaskEventEx: TTaskEventEx read get_TaskEventEx write set_TaskEventEx; { protected access }
property TaskFunc: TTaskFunc read get_TaskFunc write set_TaskFunc; { protected access }
property TaskProc: TTaskProc read get_TaskProc write set_TaskProc; { protected access }
end; { TTaskThread }
{ PThreadCtrlRec carries support data for each thread }
PThreadCtrlRec = ^TThreadCtrlRec;
{$Interfaces CORBA} { refcounting OFF }
{ IbcTaskThread is the corba/raw thread service that sleeps :o) and can be woken up,
to perform a task; be it a taskprocedure, a taskfunction(ThreadFunc) or a:
e.g.: 'class procedure ExecWait(Arg: pointer); static;' declared in a TForm \o/
messages posted in MsgQueue by the thread:
3683 = ENTE(r) -> entering execute; 2344 = BEGI(n) -> starting task
3464 = FINI(sh) -> finished task; 3663 = DONE -> going to sleep
7867 = STOP -> exiting execute, going out of business
-1 = ERRO(r) -> caught some kind of error, text is in message.
Creation: "params = [hOwner: ptrint; aMsgQ: IbcMessageQueue64; aDbgMsg: boolean]" or none.
if not if not PluginMgr.GetSvc('IbcTaskThread','bcTaskThread',taskT) then raise except...;
(i) This gives you a BLIND THREAD i.e.: ^'type', ^'name', ^obj
taskT.HandleOwner:= Form1.Handle; -then you can do like this
taskT.MsgQ:= MQ; -instead you set
taskT.DebugMsg:= true; -properties afterwards
or "pointer(taskT):= SvcMgr.GetSvcDefaultParams('IbcTaskThread',[Handle,fMsgQ,true]);"
or "PluginMgr.GetSvcDefaultParams('IbcTaskThread',[Handle,fMsgQ,true],taskT)"
i.e.: ^type, [^hForm,^MsgQ,^debugMsg(true/false)],obj
(!) NOTE: creating the thread with NIL as MsgQueue will give you NO MESSAGES!
setting 'DebugMsg' to false will have the same effect -^^-^^^^^^^^
(!) NOTE: Don't start 2 threads right after another, leave a little pause ~ 2 msecs between
(!) REMEMBER e.g.: itaskT.Obj.Free; when you're done (corba) }
ITaskThread = interface(ICorba)[SGUIDITaskThread]
{ property getters and setters }
function get_Debug: boolean;
function get_HandleOwner: ptrint;
function get_Loaded: boolean;
function get_MsgQ: IbcMessageQueue64;
function get_Sleeping: boolean;
function get_Tcr: PThreadCtrlRec;
procedure set_Debug(aValue: boolean);
procedure set_HandleOwner(aValue: ptrint);
procedure set_MsgQ(aValue: IbcMessageQueue64);
procedure set_Tag(aValue: ptrint); // property
function Tag: ptrint; // property
{ runs an extended TNotifyEvent, don't forget to synchronize / protect }
procedure CallEventEx(aTask: TTaskEventEx;anObj: TObject;aPtr: pointer);
{ ExecTask carries out the specified task with the provided data, params:
aTask = a procedure that encapsulates the task at hand
aData = a pointer to the data necessary for the task to complete;
if the task produces a result, it must be returned in the 'aData' object.
Note: REMEMBER synchronization / protection of 'aData' }
procedure ExecTask(aTask: TTaskProc;aData: pointer);
{ runs a standard TNotifyEvent, don't forget to synchronize / protect }
procedure RunEvent(aTask: TTaskEvent;aData: TObject);
{ StartTask carries out the specified task with the provided data, params:
aTask = a function that encapsulates the task at hand (same as for 'BeginThread')
aData = a pointer to the data necessary for the task to complete;
if the task produces a result, it must be returned in the 'aData' object.
Note: REMEMBER synchronization / protection of 'aData' }
procedure StartTask(aTask: TTaskFunc;aData: pointer);
function Terminate: boolean;
property DebugMsg: boolean read get_Debug write set_Debug;
property HandleOwner: ptrint read get_HandleOwner write set_HandleOwner;
property Loaded: boolean read get_Loaded;
property MsgQ: IbcMessageQueue64 read get_MsgQ write set_MsgQ;
property Sleeping: boolean read get_Sleeping;
property Tcr: PThreadCtrlRec read get_Tcr;
end;
{ IbcSleepingThread adds the possibility to change msgQ on the fly (not that you should);
can be woken up to perform a task; be it a taskprocedure, a taskfunction(ThreadFunc) or a:
e.g.: 'class procedure ExecWait(Arg: pointer); static;' declared in a TForm \o/
Creation = "constructor Create(hOwner: ptrint; aMsgQ: IbcMessageQueue64; aDbgMsg: boolean);"
messages posted in MsgQueue by the thread:
3683 = ENTE(r) -> entering execute
2344 = BEGI(n) -> starting task
3464 = FINI(sh) -> finished task
3663 = DONE -> going to sleep
7867 = STOP -> exiting execute, going out of business
-1 = ERRO(r) -> caught some kind of error, text is in message.
(!) NOTE: creating the thread with NIL as MsgQueue will give you NO MESSAGES!
setting 'DebugMsg' to false will have the same effect -^^-^^^^^^^^
(!) NOTE: Don't start 2 threads right after another, leave a little pause ~ 2 msecs between
(!) REMEMBER e.g.: itaskT.Obj.Free; when you're done (corba) }
ISleepingThread = interface(ITaskThread)[SGUIDISleepingThread] end; { ISleepingThread }
{$Interfaces COM} { refcounting back ON }
{ TThreadCtrlRec carries support data for each thread }
TThreadCtrlRec = record
tcDataF: pointer; { data for use in task-f }
tcDataP: pointer; { data for use in task-p & taske-eventex }
tcEvent: IEvent; { an event that controls the sleeping }
tcObjEv: TObject; { data for use in task-event & taske-eventex }
tcSleeping: boolean; { is the thread sleeping }
tcTerminated: boolean; { has the thread been shutdown? }
tcThread: TTaskThread; { a working thread, that sleeps and then carries out its task }
end; { TThreadCtrlRec }