Jump to content

Sonjli

Members
  • Content Count

    94
  • Joined

  • Last visited

Everything posted by Sonjli

  1. Sonjli

    Scheduled tasks at system time

    Because I need to be in strict control with the scheduling and I am in cross development (Linux and Windows at least). Interesting... any example? I know I can do something like this in OTL, so a "standard" example could help me to figure out.
  2. Hi guys, I hope this is the right topic to place my doubts. I use a DLL written in C and it need some work with pointers. I admit I am not very prepared with pointers (scholastic remembrances), so I hope my question to be clear. I have this structure: PODBALMMSG2 = ^ODBALMMSG2; ODBALMMSG2 = packed record alm_no: LongInt; atype: SmallInt; axis: SmallInt; dummy: SmallInt; msg_len: SmallInt; alm_msg: array [0 .. 63] of AnsiChar; end; And this is the function I use to populate this structure and read it: procedure TRdAlmMsgActionA.InternalRdAlmMsg; var iAlarm: Integer; LErrorCounter: Integer; rn: SmallInt; popmsg: PODBALMMSG2; begin FPath := ''; LErrorCounter := 0; // A random number the DLL need to have any initial value rn := 50; try // A pre-filled number with "max paths" (FConnection.MachinePaths) to read from DLL for var J := 1 to FConnection.MachinePaths do begin // A DLL function to loop between "Paths" until "FConnection.MachinePaths" FConnection.ErrHandle := cnc_setpath(FConnection.ConnHandle, J); if FConnection.ErrHandle <> EW_OK then begin Inc(LErrorCounter); Continue; end; // Here I need help: is this algorithm ok? new(popmsg); try // The DLL fill "popmsg" with an array of "PODBALMMSG2" with length "rn" FConnection.ErrHandle := cnc_rdalmmsg2(FConnection.ConnHandle, -1, rn, popmsg); if FConnection.ErrHandle <> EW_OK then begin Inc(LErrorCounter); Continue; end; // Loop for "popmsg" of length "rn" for var I := 0 to rn - 1 do begin // Here I do reading stuff with "popmsg^.alm_no", "popmsg^.aType", etc. // Incremet pointer to read next array value Inc(popmsg); end; finally // Bring the pointer at the start of the array Dec(popmsg, rn); // Free the pointer Dispose(popmsg); end; end; finally cnc_setpath(FConnection.ConnHandle, 0); end; end; I have so many doubts about this: - Have the popmsg pointer to be brought at the start before dispose? - Is the loop right? - Is the "new()" function right to allocate the pointer? - And so on... Any help? Thanks in advance. Eddy
  3. Hi, I have this case where one OmniTask run some external code from a delphi library\Component that uses internally a TThread. This thread can't be accessed from outside. This external library have a class which listen for an incoming request and when this happens then it run a "onReceive" event. Something like a listening socket. One OmniTask "run" one and only one of these objects. Have I to pay attention when the "inside-thread" have to use write-resources of the Omnitask? For example when the "inside-thread" need to use the logger of the OmniTask? Some pseudo code: CreateTask( procedure(const task: IOmniTask) var lBroadcaster: IBroadcastManager; lLogger: ILogWriter; begin [...] task.Lock.Acquire; try lLogger.Log(TLogType.Info, 'Testing...', 'TEST'); finally task.Lock.release; end; [...] // lBroadcaster is the object using an internal tthread lBroadcaster.OnReceive := procedure(ABroadcastMessage: IBroadcastMessage) begin task.Lock.Acquire; try try lLogger.Log(TLogType.Info, 'Parsing...', 'TEST'); [...] except on E: Exception do begin lLogger.Log(TLogType.Error, 'Exception (%s): "%s"', [E.ClassName, E.Message], 'TEST'); end; end; finally task.Lock.release; end; end; lBroadcaster.Connect('127.0.0.1', 'guest', 'guest', True); ).SetParameter([...]) // All my stuff injiections .WithLock(CreateOmniCriticalSection) .Run; Is the locking mechanism used in the right way? Thanks Eddy
  4. The API is documented and I used it for years. The my only problem is about pointers... I know, don't say a word 😉 Do you have any Pascal related documentation\manual about pointers? Thanks everybody. Eddy
  5. Thank you Anders, really precious. As you see I use the FOCAS library to connect some CNC and sometimes there are some traps... Are you skilled with FOCAS? May I ask you any questions sometimes if I am in danger? 😅
  6. Hi Cristian, thanks for your answer. How do I allocate popmsg? How do I dispose the array? How do I read an element? @popmsg[4].alm_no or popmsg[4]^.alm_no? Eddy
  7. Hi, simple question: how can I run a pipeline more than one time in the same method\procedure\function? I do like this ... MyPipeline := Parallel .Pipeline .stage(myStage1) .stage(myStage2); ... procedure MyProcedure; begin // First run MyPipeline.Run; MyPipeline.input.Add('ONE'); aValue := MyPipeline.Output.Next; // I tries also this... without success MyPipeline.Cancel; MyPipeline.WaitFor(INFINITE); // I do some stuff in the middle // First run MyPipeline.Run; // Here I receive "Pipeline is already running", but I don't think so... :( MyPipeline.input.Add('TWO'); aValue := MyPipeline.Output.Next; ... end; I am not finding any info in the docs. In the sources of IOmniPipeline I see a "opCountStopped" semaphore that is checked "Assigned" in the first run... but I really don't understand why this limits one instance of a IOmniPipeline to be run only one time in the same method. Thanks again Eddy
  8. Sonjli

    Pipeline multi runnable

    Hi, sorry for late reading. I am trying to build a kind of a "protocol runner". I need an object which can accept different "actions" and then it can be run in loop to repeat the protocol. Example: Name: "Protocol 1: download a file with locks" 1. Wait until "the other" lock file disappear 2. Put "my" lock file in that folder 3. Download the main file 4. process the main file 5. Delete "my" lock file 7. Wait 5 seconds 8. Restart from 1 The entire loop must be run in a separate non-blocking thread. But every loop must be serialized. I thought that pipeline could be the answer, but I can't run it several times in that loop. I may use a state machine (https://github.com/malcolmgroves/TStateMachine) but I need to build several protocols changing one or more "actions" at runtime... I don't know if this is the right choice. Is my idea clear enough? I hope so... 🙂 Thanks
  9. Hi (here again...), I have a doubt about delegation. I have this simple case TWSGuardian = class(...) strict private FOnNotResponding: TProc<Integer>; ... public // Delegation property OnNotResponding: TProc<Integer> read GetOnNotResponding write SetOnNotResponding; end; // OTL task ... Task.Comm.Send(MSG_WSNOTRESPONDING, TOmniValue.CreateNamed(['timeout', LPassedTime])); end; end; end ) .OnMessage(MSG_WSNOTRESPONDING, procedure(const Task: IOmniTaskControl; const msg: TOmniMessage) begin DoNotResponding(msg.MsgData['timeout']); end ); ... procedure TWSGuardian.DoNotResponding(TimeOut: Integer); begin if Assigned(FOnNotResponding) then FOnNotResponding(TimeOut); end; ... When calling the TWSGuardian object I would use a critical section to avoid collisions in case of more than one running TWSGuardian. Like here: begin Grd := TWSGuardian.Create; ... Grd.OnNotResponding := procedure(ATimeOut: Integer) begin if ATimeOut > 1000 then begin // Critical section? RunSomeAlienCode; // How can I be sure this is thread-safe? end; end; ... Grd.Run; ... Grd.Stop; // This safely terminate the task inside TWSGuardian Is this the right way? Is there a common used pattern? How can I move the critical section inside my TWSGuardian instead of using it in the main thread? I am a bit confused. Thanks and sorry for this PITA
  10. Sonjli

    Delegation good practice

    Hi Primoz, yes, my example is not so clear. My idea is of making something like a "Guardian\watchdog" (ok, they are not the same...) service who calls an url every X seconds, and if it does not respond then it delegates the calling service to do whatever it wants (it can, for example, stop the running service and restart). I thought the solution was of using the "OnMessage" technique and delegates there the calling service. I don't know if this is the right pattern, nor the right solution, indeed. I hope to be more clear... Thanks
  11. Hello guys, I am working to port a NTService with a WebBroker application (wrapping Daniele Teti's DMVC) from TThread style to OTL. It's almost ok (and amazing, yes!) but in the next code the "OnTerminated" event never triggers (I never see the "Server stopped" string in the log)... What am I wrong? Thank you in advance ... LServer := TIdHTTPWebBrokerBridge.Create(nil); FRunner := CreateTask( procedure(const Task: IOmniTask) var LMvc: TIdHTTPWebBrokerBridge; i: Integer; begin LMvc := Task.Param.ByName('mvc'); RunServer(8889, LMvc); try repeat Sleep(25); {$IFDEF DEBUG} inc(i); if (i mod 40) = 0 then Task.Comm.Send(MSG_LOG, 'Keep Alive'); {$ENDIF} until Task.Terminated; finally StopServer(LMvc); end; end ) .SetParameter('mvc', LServer) .OnMessage( procedure(const Task: IOmniTaskControl; const msg: TOmniMessage) begin if msg.MsgID = MSG_LOG then begin Log.Debug(msg.MsgData, ''); // LogMessage(msg.MsgData, EVENTLOG_INFORMATION_TYPE); end; end ) .OnTerminated( procedure(const Task: IOmniTaskControl) begin Task.Comm.Send(MSG_LOG, 'Server stopped'); if Assigned(Task.FatalException) then begin var ELocal := Task.DetachException; Task.Comm.Send(MSG_LOG, Format('...with Errors: "%s"', [ELocal.Message])); end; end ); ... // In the ServiceStart event ... FRunner.Run; ... // In the ServiceStop event ... FRunner.Terminate; ...
  12. Sonjli

    OnTerminated never triggers

    Hi Primoz, It's all clear. Very clear. This is a new precious info, for me. Where did you get these infos? Only by debugging? ServiceCreate is in one thread, and ServiceStart/ServiceStop in second thread or every event is in a separate thread? (so are they three?) This is the second precious info. Some of my test are closed. This has perfectly sense Thank you very much.
  13. Sonjli

    OnTerminated never triggers

    Hi, I attach a mock project with the "OnTerminated" event not firing. - The project is an NTService, so you have to install with "/install" - I write the logs (a bit verbose...) on the default Windows Event Monitor (under Windows\Application) To reproduce - Install - run the service - wait a punch of seconds - Stop the service (not pause, it is not implemented for this purpose) - Open Event Monitor - The messages linked to "OTL.NTService" Origin finish with a serie like this: Keep Alive A try to stop task... FRunner.ExitCode = 0 ServiceStop You'll never find a "Server stopped in ONTERMINATED" message, that is the one fired inside the "OnTerminated" event. I hope to be clear... Thanks again. PS: I use D10.3.1 but I think the sources can be good for oldest versions. OmniThreadNTService.zip
  14. Hi, as in title, I have this crash with all the downloadable and compatible versions in http://mmx-delphi.de I have the same report as here:
  15. Sonjli

    10.3.1 Rio (26.0.332194899) crash

    Thank you. Your tool is a must for my team. I try asap! EDIT: I tried and it works like a charm. Thanks again. PS: Is it in your plan to add default D10.3 themes?
  16. Hi, I am trying to use your fantastic library (thanks for it). I have a doubt about freeing memory. I have a master thread (a standard TThread by Delphi) that is responsible to run some omni tasks. I use to do it in this way: procedure TThreadMonitorBroadcast.Execute; begin ... while not GetArticoloVersato.getTabella.Eof do begin ... ATaskList := CreateTaskControlList; try // Run all registered threads FBroadcastActions.ForEach(Action<IBroadcastAction>( procedure(ABroadcastAction: IBroadcastAction) begin ATaskList.Add(CreateTask( procedure(const Task: IOmniTask) begin Sleep(100); // Only for test // ABroadcastAction.Run(Task, GetMacchina); end).MonitorWith(FEventMonitor).Join(otlWaitGroup).Schedule(otlPool)); end )); otlWaitGroup.WaitForAll; if otlPool.CountExecuting > 0 then raise Exception.Create('Oh my..., thread still running'); ATaskList.Clear; finally ATaskList := nil; end; ... end; ... end; It looks like everything works finem but RAM is increasing at every loop. What am I wrong? I tried to use a TaskControlList, but without success.... Thanks in advance Eddy
  17. Sonjli

    Newbie: memory management

    OK, but THAT is the problem... if I create the group outside the loop then memory increase; if I put that inside the loop, memory is stable. Anyway, I am trying with background workers. They are awesome.
  18. Sonjli

    Newbie: memory management

    Thanks Olivier. I'll try the background workers. For the sentence: Sorry, but I didn't understand... (maybe my poor english? 🙂 )
  19. Sonjli

    Newbie: memory management

    While experimenting I found that the problem is the creation of the otlWaitGroup. I created it out of the main loop; so now I moved it inside the loop like in the code below. I have some doubts: Why the reference to OmniTasks stay inside the WaitGroup until it is detroyed? Are they weak references? Why do I have to create many waitGroups instead of creating only one, and use it many times? Thanks anyone. while not GetArticoloVersato.getTabella.Eof do begin ... ATaskList := CreateTaskControlList; otlWaitGroup := CreateTaskGroup; // Here create it try // Run all registered threads FBroadcastActions.ForEach(Action<IBroadcastAction>( procedure(ABroadcastAction: IBroadcastAction) begin  ATaskList.Add(CreateTask( procedure(const Task: IOmniTask)  begin Sleep(100); // Only for test // ABroadcastAction.Run(Task, GetMacchina); end).MonitorWith(FEventMonitor).Join(otlWaitGroup).Schedule(otlPool)); end )); otlWaitGroup.WaitForAll; if otlPool.CountExecuting > 0 then raise Exception.Create('Oh my..., thread still running'); ATaskList.Clear; finally otlWaitGroup := nil; // Here free it ATaskList := nil; end; ... end;
×