multithreading - Can TOmniEventMonitor be used in a background thread? -
original question
in our delphi xe4 application use tomnieventmonitor receive messages other tasks. long running in main thread, works fine, once put same code in task, tomnieventmonitor stops receiving messages. have included simple example of below -- clicking button_testinmainthread results in file being written expected, clicking button_testinbackgroundthread not. design, or there way working while still using tomnieventmonitor?
unit mainform; interface uses winapi.windows, winapi.messages, system.sysutils, system.variants, system.classes, vcl.graphics,vcl.controls, vcl.forms, vcl.dialogs, vcl.stdctrls, otltask, otltaskcontrol, otlcomm, otleventmonitor; const my_omni_message = 134; type tomnieventmonitortester = class(tobject) fname : string; fomnieventmonitor : tomnieventmonitor; fomnitaskcontrol : iomnitaskcontrol; constructor create(aname : string); destructor destroy(); override; procedure handleomnitaskmessage(const task: iomnitaskcontrol; const msg: tomnimessage); end; ttestlaunchertask = class(tomniworker) fomnitaskmonitortester : tomnieventmonitortester; function initialize() : boolean; override; end; tform1 = class(tform) button_testinmainthread: tbutton; button_testinbackgroundthread: tbutton; procedure button_testinmainthreadclick(sender: tobject); procedure button_testinbackgroundthreadclick(sender: tobject); private fomnieventmonitortester : tomnieventmonitortester; ftestlaunchertask : iomnitaskcontrol; end; var form1: tform1; implementation {$r *.dfm} procedure omnitaskprocedure_oneshottimer(const task: iomnitask); begin sleep(1000); task.comm.send(my_omni_message); end; constructor tomnieventmonitortester.create(aname : string); begin inherited create(); fname := aname; fomnieventmonitor := tomnieventmonitor.create(nil); fomnieventmonitor.ontaskmessage := handleomnitaskmessage; fomnitaskcontrol := fomnieventmonitor.monitor(createtask(omnitaskprocedure_oneshottimer)).run(); end; destructor tomnieventmonitortester.destroy(); begin fomnieventmonitor.free(); inherited destroy(); end; procedure tomnieventmonitortester.handleomnitaskmessage(const task: iomnitaskcontrol; const msg: tomnimessage); var filename : string; f : textfile; begin filename := includetrailingpathdelimiter(extractfiledir(paramstr(0))) + fname + '.txt'; assignfile(f, filename); rewrite(f); writeln(f, fname); closefile(f); end; function ttestlaunchertask.initialize() : boolean; begin result := inherited initialize(); if result begin fomnitaskmonitortester := tomnieventmonitortester.create('background'); end; end; procedure tform1.button_testinmainthreadclick(sender: tobject); begin fomnieventmonitortester := tomnieventmonitortester.create('main'); end; procedure tform1.button_testinbackgroundthreadclick(sender: tobject); begin ftestlaunchertask := createtask(ttestlaunchertask.create()).run(); end; end.
additional observations
with following code seems possible use tomnieventmonitor within background thread. clumsy solution -- iomnitwowaychannel gets created not used in meaningful way -- try simplify code commenting out either of lines marked "don't remove!", handletaskmessage doesn't called more. can tell me doing wrong here?
unit mainform; interface uses winapi.windows, winapi.messages, system.sysutils, system.variants, system.classes, vcl.graphics, vcl.controls, vcl.forms, vcl.dialogs, vcl.stdctrls, dsiwin32, gplists, otltask, otltaskcontrol, otlcommon, otlcomm, otleventmonitor; const my_omni_message = 134; type tomnieventmonitortesttask = class(tomniworker) fomnitaskcontrol : iomnitaskcontrol; fomnitwowaychannel : iomnitwowaychannel; fomnieventmonitor : tomnieventmonitor; function initialize() : boolean; override; procedure handletaskmessage(const task: iomnitaskcontrol; const msg: tomnimessage); procedure handletaskterminated(const task: iomnitaskcontrol); end; tform1 = class(tform) button_testinbackgroundthread: tbutton; procedure button_testinbackgroundthreadclick(sender: tobject); private ftesttask : iomnitaskcontrol; end; var form1: tform1; implementation {$r *.dfm} procedure omnitaskprocedure_oneshottimer(const task: iomnitask); begin sleep(1000); task.comm.send(my_omni_message); // don't remove! (task.param['comm'].asinterface iomnicommunicationendpoint).send(my_omni_message); end; procedure tomnieventmonitortesttask.handletaskmessage(const task: iomnitaskcontrol; const msg: tomnimessage); var filename : string; f : textfile; begin filename := includetrailingpathdelimiter(extractfiledir(paramstr(0))) + 'handletaskmessage.txt'; assignfile(f, filename); rewrite(f); writeln(f, 'handletaskmessage!'); closefile(f); end; procedure tomnieventmonitortesttask.handletaskterminated(const task: iomnitaskcontrol); var filename : string; f : textfile; begin filename := includetrailingpathdelimiter(extractfiledir(paramstr(0))) + 'handletaskterminated.txt'; assignfile(f, filename); rewrite(f); writeln(f, 'handletaskterminated!'); closefile(f); end; function tomnieventmonitortesttask.initialize() : boolean; begin result := inherited initialize(); if result begin fomnieventmonitor := tomnieventmonitor.create(nil); fomnieventmonitor.ontaskmessage := handletaskmessage; fomnieventmonitor.ontaskterminated := handletaskterminated; fomnitwowaychannel := createtwowaychannel(); task.registercomm(fomnitwowaychannel.endpoint1); // don't remove! fomnitaskcontrol := fomnieventmonitor.monitor( createtask(omnitaskprocedure_oneshottimer) ).setparameter('comm', fomnitwowaychannel.endpoint2).run(); end; end; procedure tform1.button_testinbackgroundthreadclick(sender: tobject); begin ftesttask := createtask(tomnieventmonitortesttask.create()).run(); end; end.
there no problem tomnieventmonitor running inside of thread, provided there message pump handling messages it. put block of code demonstrate. works expected.
procedure tmythread.execute; var message: tmsg; begin freeonterminate := true; fomnieventmonitor := tomnieventmonitor.create(nil); fomnieventmonitor.ontaskmessage := handleomnitaskmessage; fomnitaskcontrol := fomnieventmonitor.monitor(createtask(omnitaskprocedure_oneshottimer)).run(); try while not terminated begin if msgwaitformultipleobjects(0, nil^, false, 1000, qs_allinput) = wait_object_0 begin while peekmessage(message, 0, 0, 0, pm_remove) begin translatemessage(message); dispatchmessage(message); end; end; end; fomnitaskcontrol := nil; fomnieventmonitor.free; end; end;
from can see, tomnitaskexecutor waits messages specific handles. in code example, it's terminate event , couple of comm handles. messages tomnieventmonitor never processed.
changing ttestlaunchertask.initialize
following results in correctly writing out file. donothingproc
empty method on class.
function ttestlaunchertask.initialize() : boolean; begin result := inherited initialize(); if result begin fomnitaskmonitortester := tomnieventmonitortester.create('background'); // tell task event monitor task.registerwaitobject(fomnitaskmonitortester.fomnieventmonitor.messagewindow, donothingproc); end; end;
i adding message window tomnieventmonitor task waitobject list handle registered msgwaitformultipleobjectsex
call , waiting remi , david tear message handling shreds :)
Comments
Post a Comment