Jump to content

DavidJr.

Members
  • Content Count

    55
  • Joined

  • Last visited

Everything posted by DavidJr.

  1. Hi, On a fairly large sized application with a few threads doing most of the work the UI does have 2 timers for updating fields based on calls to Thread class properties, I get a almost consistent pauses in the UI (ie... progress bar updates, TRichEdit line adds and TLabel caption updates) unless my mouse pointer is moved over the window. This is on a PC with two monitors. Is there something I can call to keep the UI from pausing? I tried finding other posts that ask this before posting here. Thanks. David
  2. thats exactly what I did. thanks.
  3. DavidJr.

    TVideoCaptureDevice will not run in (Delphi 10.2.3)

    Sorry just my luck I'd leave out some information. This is a Windows 10 OS, NOT Android.
  4. thanks. I resolved that issue, I should have replied sooner. I have long running procedure holding up the UI those same procedures replied on UI values as well.
  5. that's an interesting idea. I want to add that it seems to be message related. So if I move the mouse outside the window and the procedure finishes the TTask.Wait() then it pauses after a long run... then I can move the mouse around (without clicking on another window) and it resumes and finishes like its supposed to. But adding in booleans to allow a triggered set of actions in the Timer handler to maybe create messages is worth a try. When I did strictly linux/unix programming I never had these issues, Windows is definitely a complex system.
  6. Also I do call CheckSynchronize from the main UI, there is no problem getting information from threads to main UI.
  7. yes, it would be a problem, but I am not doing that. I call a property and a "getter" method will return a value, and that all works fine. The issue is in the methods that reside in the UI thread that do work. Not everything is in a separate thread, but all the heavy work is in separate threads, but the act of pulling in tmp files is all in the main UI thread and the reason is its a legacy app that I have not the abilty to do a complete re-write. Now the procedure that is called by a timer event is a big one and so I must disable the timer until the procedure completes, the procedure does call other methods. I wished I could share the source but its big and a lot of unrelated code that works exactly as intended its only the stuff that's called in the UI. I know its preferred to post source code, but this code isn't something I own and its against the company policy.
  8. The actions in the timer do work, but methods running in UI thread are not finishing (writing to fields or increasing progressbar) unless my mouse is in the window.
  9. DavidJr.

    TSimpleEvent how to

    Hi, I am trying to understand TSimpleEvent (or TEvent) and complete documentation with examples doesn't seem to be so easy to find. I suspect that it can be used as a trigger more effectively than a boolean, but I am not so sure without a better understanding. I would like to create a one time trigger that is set as an event so a procedure can execute. The procedure unset it and set another Event to allow for a waitfor() like procedure to wait for the procedure to finish work. IS my understanding of a TSImpleEvent in that it can serve as a trigger correct? Also how is it turned on and off? I got the idea from Bechhoff's TwinCAT3 environment where there is a Trigger object that once its read its automatically turned off so to NOT allow a method called by the trigger to be called more than once. Thanks.
  10. DavidJr.

    TSimpleEvent how to

    This is helpful. Other than this page: https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.SyncObjs.THandleObject.WaitFor , I did not see these pages until you provided links: https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.SyncObjs.TEvent.SetEvent https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.SyncObjs.TEvent.ResetEvent Thank you for the info.
  11. DavidJr.

    TSimpleEvent how to

    Yes. I saw those. But I do not know from those pages the proper way to use SetEvent or ResetEvent or any properites or other methods. No example code like you would expect from TTask and the like. More specifically What is SetEvent doing vs ResetEvent? Which thread has rights to these methods?
  12. I have a question regarding TThread class instances vs using TTasks. Is there a way to get 2 long running Tthread classes to run on separate CPU cores instead of using TTasks instances? I would like to have to threads run the entire time the app is open be ready to run some procedures. They do this just fine, however, I just read up on TTasks and Delphi Parallel Programming Library, and I understand that the benefit is an automatic optimization of tasks by balancing the CPU load of each core.. but all I want to do is ensure that each thread run on a different core from each other. Thanks.
  13. Ok, thats good to know. Maybe this is a really dumb question, but why isn't the TThread class instances handled the way TTask instances are from the beginning? I am assuming that Any TThread instance I create and execute will run on the same core as my mainform thread, is this true?
  14. Hi, I have an application that takes CAD model data and slices it until layers then posts these layers as binary data using Indy and IdMultipartForm (AddFile()). I am usually not allowed to ask for help outside the company because of the proprietary information, but I will do my best at giving as much information as I can. Most of the time this just works but occasionally I get the following: System.SysGetMem(Opt.out) System._GetMem(???) System._NewUnicodeString(1) System._UStrFromPWCharLen('','sA',1) System._UStrFromWChar(???,'s') IdGlobalProtocols.FindFirstNotOf(#9' ','slice',5,1) IdCoderHeader.DecodeHeader('slice') IdCoderHeader.EncodeHeader('slice','','B','UTF-8') IdMultipartFormData.TIdFormDataField.FormatHeader IdMultipartFormData.TIdFormDataField.GetFieldSize IdMultipartFormData.TIdMultiPartFormDataStream.CalculateSize IdMultipartFormData.TIdMultiPartFormDataStream.IdSeek(???,???) IdGlobal.TIdBaseStream.Seek(???,???) System.Classes.TStream.GetSize The application receives the data from a queue, processes it with 100% success, and then the file is written locally to a a disk, then I do the following: // EDITED: took out "BAD SECTIONS" in attempt to get a better response. function TMain.SaveTheSolvedSlice(FileName: String): Boolean; var MimeType, Response: String; jsonVal: TJSonValue; Stat, Size: String; SendParams: TIdMultiPartFormDataStream; TOPLSliceFile: TStream; //HTTPSendFile: TIdHTTP; begin Result := False; Response := 'NULL'; HTTPSendFile.Request.Clear; HTTPSendFile.ReadTimeout := 2000; HTTPSendFile.ConnectTimeout := 9000; SendParams := TIdMultiPartFormDataStream.Create; Application.ProcessMessages; try if(FileExists('tmp\out\'+FileName)) then begin MimeType := 'application/octet-stream'; While(GetFileSizeInBytes('tmp\out\'+FileName) < MinSliceSizeFromUnsolvedFile+1) Do Delay(10); //Params.AddFormField('_token', 'Myfb9OqYgDBwDws3zTL9QOs492XWfNtGLftUdNsH'); SendParams.AddFile('slice', 'tmp\out\'+FileName, MimeType).ContentTransfer:='binary'; Sleep(10); SendParams.Position := 0; try While(GetFileSizeInBytes('tmp\out\'+FileName) > SendParams.Size) Do Delay(10); finally end; StatusUpdate(Console, 'Attempting to post file '+'tmp\out\'+FileName+' (size: '+SendParams.Size.ToString+' bytes)'); Delay(10); Response := HTTPSendFile.Post(STORAGE_OUT_REPO, SendParams); Delay(5); if(Response <> 'NULL') then begin //{"Slice":{"Status":"ACCEPTED","FileName":"1_Some_Job_Filename.slc","Size":1812}} jsonVal := TJSonObject.ParseJSONValue(Response); Stat := jsonVal.GetValue<String>('Slice.Status'); Size := jsonVal.GetValue<String>('Slice.Size'); jsonVal.Free; StatusUpdate(Console, 'Toasted Slice (size: '+Size+') '+Stat.ToLower); if(Stat = 'ACCEPTED') then Result := True else if(Stat = 'ERROR') then Result := False else Result := False; end; end finally SendParams.Free; Response := 'NULL'; HTTPSendFile.Response.Clear; end; end; I do the comparison of size of original file to that of the Params, which I expect to be slightly larger, to ensure the file has finished writing to disk, then loaded as a File in TIdMultiPartFormDataStream before attempting to post back to API. I suspect that I am trying to get the the size of the Params object too soon, is that likely? Also I use the Indy IdHTTP as object that I dragged into the form, which works better than declaring a new instance and freeing it every time I process a new file. Also note: the method GetFileSizeInBytes() is a method I created a few years back based on example code and always works.
  15. So I verified that there are memory leaks which are listed in the screenshot attached. There are no others that come up with other than these and consistently reproducible when I use IdHTTP Post with use a TIdMultiPartFormDataStream instance local to the procedure. I tried both (not at the same time): SendParams.AddFile('slice', FullFilePath, MimeType).ContentTransfer:='binary'; SendParams.AddFormField('slice', MimeType, '', SolvedSliceStream, FileName).ContentTransfer := 'binary'; So I am going to use MadExcept with this project, but as I posted before is there an issue with the version (of Indy) that came with Delphi/RADStudio 10.2.3 (Tokyo) Enterprise? Or could the issue be with TStream type objects?
  16. I went back to the TIdHTTP client and I discovered that I get the error again. I will search tomorrow for what could be causing the issue in memory allocation made by the call to IndyFormat(). It always happens after a few successful posts. But I wanted to point out that I am using Delphi Tokyo (10.2.3) and the version of Indy that came with that package. Should I upgrade to a newer version?
  17. To start I will answer a question that was asked: The Getters and Setters were put in place for the purpose of reading a value or initializing a value only, but all the work is done in the (for lack of a better term) back-end thread. So there is some sorting and data manipulation that takes place with these array of records. Also in the "backend thread" I need to keep track of a "global index" to track where I am at as I process/copy the original array of record. Ultimately the new data in the second array of record will replace the first array of record before being written to a file. It all just works however, its a careful juggling of data that is very complex. It was this way before I started working on it. Someone mentioned a "data module", this sounds like a class just for the data, am I understanding this correctly? right off the bat I am trying to identify what global variables can actually be localized in the methods they are used in. But from there, the data that needs to be visible within the "backend" thread instance (and all its methods). I think if I write this from the ground up I would have maybe created a parent class with the data available, however I do not see how an array of record can be used as a property.
  18. My Timer event handler was causing an issue. That is fixed and my code works now. I processed 100 layers and its all good. Calling a destroyed HTTP object is bad too .. my bad.
  19. @Remy Lebeau, This morning I went through the thread that processes the data and exports the data to a binary file. Any object created is Freed after use in every method. Also I Set Array lengths back minimal size. I made the following changes: SendParams: TMultipartFormData; //TIdMultiPartFormDataStream; HTTPPostfile: TNetHTTPClient; //IdHTTP; HTTPResp: IHTTPResponse; and that particular problem went away. However now I have a issue with My Habari RabbitMQ client. Not sure its appropriate to post in this thread since its not Indy. But What I will share here and maybe your wisdom can point me in the right direction. The main thread (TForm VCL), I use a timer with interval of 5 seconds, the Timer handler method sets the Timer.Enabled to False until it completes the work of getting a message from the MQ then using the data to get the file, then calls a method from the second thread to process the data and write to binary file. Once its done, the File is posted back to web api. Now is it problematic to use a timer this way? Also the Habari RabbitMQ library is created in the main thread (VLC) and destroyed there. I followed everything according to documentation. Another note to add the code was inherited from a previous developer... the algorithms just work for data processing, the problem is in this app that interacts with network services, I mean no problems seems to come up on methods with the data processing such as Access Violations... I am also requesting from my boss to enlist outside help with this. Thanks.
  20. @Remy Lebeau thanks again. I am not sure if you are asking if am reporting a "memory leak" in the Indy software or in my code? I am not aware of a memory leak anywhere in the code that posts the file using IdHTTP Post. But I will try looking closer with SysInternals Process Explorer, as a last resort use a TStream directly.
  21. I was using this: function GetFileSizeInBytes(const fn: string): integer; var sr : TSearchRec; begin if FindFirst(fn, faAnyFile, sr ) = 0 then result := Int64(sr.FindData.nFileSizeHigh) shl Int64(32) + Int64(sr.FindData.nFileSizeLow) else result := -1; FindClose(sr); end; but when I stopped calling it the problem at first seemed to go away. Then then came up again. The only place the file is opened is when its created, I made some changes but essentially its the same logic: function ExportSliceToBinFile(MyFileName: String): Integer; var I: Integer; MyOPLToolPathFile: TFileStream; FullFilePath: String; begin Result := 0; if(Not DirectoryExists('tmp')) then CreateDir('tmp'); if(Not DirectoryExists('tmp\out')) then CreateDir('tmp\out'); FullFilePath := 'tmp\out\'+MyFileName; MyOPLToolPathFile := TFileStream.Create(FullFilePath, fmCreate); try try FOR I := 1 TO GlobalToolpathIndex DO begin MyOPLToolPathFile.WriteBuffer(NewOPLToolPath[I], SizeOf(OPL_COMMAND_RECORD)); end; Result := MyOPLToolPathFile.Size; except Result := -1; end; finally FreeAndNil(MyOPLToolPathFile); end; end; this time I pass the size back as the return.. The method that Posts the binary file I used some of your suggestions like this: function TMain.SaveTheSolvedSlice(FileName: String): Boolean; var MimeType, Response, FullFilePath: String; jsonVal: TJSonValue; Stat, Size: String; SendParams: TIdMultiPartFormDataStream; Retries: Integer; begin Result := False; Retries := 0; FullFilePath := 'tmp\out\'+FileName; if (not FileExists(FullFilePath)) then Exit; Response := 'NULL'; HTTPSendFile.Request.Clear; HTTPSendFile.ReadTimeout := 2000; HTTPSendFile.ConnectTimeout := 9000; SendParams := TIdMultiPartFormDataStream.Create; MimeType := 'application/octet-stream'; try SendParams.AddFile('slice', FullFilePath, MimeType).ContentTransfer:='binary'; ActivityPanel.Text := 'HTTP Post Slice'; StatusUpdate(Console, 'Attempting to post file '+FullFilePath+' (size: '+ IntToStr(SOLVED_FILESIZE) +' bytes)'); repeat try Response := HTTPSendFile.Post(STORAGE_OUT, SendParams); except on E: EFOpenError do // I know, this is not the best option, but it is the only way to detect // a sharing violation error with TFileStream. The alternative is to call // CreateFile/FileOpen() and GetLastError() directly, and then create a // THandleStream from the result... StatusUpdate(Console, E.Message); end; Inc(Retries); Delay(250); until (Response <> '') OR (Retries > 10); if(Response <> 'NULL') AND (Response <> '') then begin //{"Slice":{"Status":"ACCEPTED","FileName":"1_Some_Job_Filename.slc","Size":1812}} jsonVal := TJSonObject.ParseJSONValue(Response); try Stat := jsonVal.GetValue<String>('Slice.Status'); Size := jsonVal.GetValue<String>('Slice.Size'); finally jsonVal.Free; end; StatusUpdate(Console, 'Toasted Slice (size: ' + Size + ') ' + Stat.ToLower); Result := (Stat = 'ACCEPTED'); end; finally SendParams.Free; Response := 'NULL'; HTTPSendFile.Response.Clear; end; end; yest I still get this: System.SysGetMem(Opt.out) System._GetMem(???) System._NewUnicodeString(3) System._UStrAsg('',???) System._CopyArray($12F228,$12F3B0,???,5) System._CopyRecord($12F1B0,$12F338,???) IdGlobal.IndyFormat('%s'#$D#$A'Content-Disposition: form-data; name="%s"',(...)) IdMultipartFormData.TIdFormDataField.FormatHeader IdMultipartFormData.TIdFormDataField.GetFieldSize IdMultipartFormData.TIdMultiPartFormDataStream.CalculateSize IdMultipartFormData.TIdMultiPartFormDataStream.IdSeek(???,???) IdGlobal.TIdBaseStream.Seek(???,???) System.Classes.TStream.GetSize IdHTTP.TIdCustomHTTP.PrepareRequest($81ABC10) How do I use SysInternals Process Explorer for open files? I did download this and I have it running. I come form a Linux/Unix world some so of these tools are much different. In linux I can use lsof . I do use two different IdHTTP instances, one for Get and one for Post, that should not hurt anything right?
  22. actually this of course would result in an exception if I am repeating the same thing.. But I think my method for getting file size was not freeing in time. because when I stropped calling it everything was fine. Thanks again for the help.
  23. Thank you for the help. This shows that the file is still being used by another process. How do I fix that? This is where the file is created: function ExportSliceToBinFile(MyFileName: String): Boolean; var I: Integer; {// OPL_ToolPath_File_Type: ###DRMJ###} MyOPLToolPathFile: TFileStream; // of OPL_COMMAND_RECORD; begin if(Not DirectoryExists('tmp')) then CreateDir('tmp'); if(Not DirectoryExists('tmp\out')) then CreateDir('tmp\out'); MyOPLToolPathFile := TFileStream.Create('tmp\out\'+MyFileName, fmCreate or fmOpenWrite); try try FOR I := 1 TO GlobalToolpathIndex DO begin MyOPLToolPathFile.WriteBuffer(NewOPLToolPath[I], SizeOf(OPL_COMMAND_RECORD)); end; Result := True; except Result := False; end; finally MyOPLToolPathFile.Free; end; end; The thread that calls this is where the processing is also done. How can I make sure the file is complete released after creation?
  24. Yes.. I caught that, Actually I had renamed the other references from MyOPL... to MySliceFile so I did not have to explain any meaning behind the name but as you posted is how it really is, sorry about that. The logic involved it creating the data has been in place for years and is very consistent but also contains proprietary info.
×