Jump to content

luebbe

Members
  • Content Count

    105
  • Joined

  • Last visited

Community Reputation

26 Excellent

Technical Information

  • Delphi-Version
    Delphi 10.4 Sydney

Recent Profile Visitors

1152 profile views
  1. Got the point, thanks 🙂 I was missing the obvious part that the call stack doesn't make sense. Been digging through the RTL to find out when a EMonitorlock Exception would be raised.
  2. You're right, the call stack doesn't make sense. I'm using my own fork of loggerpro (https://github.com/luebbe/loggerpro.git) and made two PRs with additional functionality in the original, but I didn't modify any of the queuing code. We're using a very old version (6.x) of Eurekalog. Perhaps this is reason for the wrong stack trace, but still I wouldn't expect any exception to happen here.
  3. FTask is an IFuture, so yes, it should wait. I just mentioned this fact but didn't show any code. Here it is: procedure TUpdater.UpdateIndex(const ASearchPathList: string; AForceUpdate: boolean); begin ... cancel running tasks etc ... FTask := TTask.Future<TLoadStatus>( function: TLoadStatus begin Update; Result := FStatus; end); end;
  4. Hi Folks, in one ouf our projects I'm using @Daniele Teti 's loggerpro library (https://github.com/danieleteti/loggerpro) instead of a homebrew logging solution. A few weeks after switching to loggerpro, a first Eurekalog bug report came in with the message: "EMonitorLockException in ThreadSafeQueueU.pas: {ThreadSafeQueueU}TThreadSafeQueue<LoggerPro.TLogItem>.Enqueue, Zeile 157 (0)". This exception is clearly raised inside loggerpro. I have already asked at GitHub (https://github.com/danieleteti/loggerpro/issues/53), but have received no reply yet. Every month or so, another of these bug reports comes in. The problem is: - I cannot reproduce/trigger it on my development PC, even though I think I can locate exactly, where and under which circumstances it happens - I don't see any obvious error in the loggerpro code - I don't see any obvious error in my code which is why I'm asking for help here. Maybe I have missed something obvious in my code... We have the following scenario: The main thread starts a background task (IFuture), which builds up an index of files for later use. Both, main and background task log their status with LoggerPro. The index updater: procedure TUpdater.Update; var LXxxFiles, LYyyFiles: TFileList; begin if FStatus = stNotLoaded then begin Log.Debug('Renewing Index', 'INDEX'); LXxxFiles := TFileList.Create; LYyyFiles := TFileList.Create; try FStatus := stLoading; ... Prepare XXX and YYY lists ... Log.Info('Check %d Xxx Files', [LYyyFiles.Count], 'INDEX'); Log.Info('Check %d Yyy Files', [LXxxFiles.Count], 'INDEX'); // Check existing files and index their content if FStatus <> stCanceled then if Process(LXxxFiles) and Process(LYyyFiles) then FStatus := stLoaded; if FAutoSave then FIndex.Save; FIndex.LogStats; Log.Debug('Status - ' + TRttiEnumerationType.GetName<TLoadStatus>(FStatus), 'INDEX'); finally LXxxFiles.Free; LYyyFiles.Free; end; end; end; If the main task needs the index, it calls the following routine: function TUpdater.WaitForCompletion: boolean; begin Log.Enter('Updater.WaitForCompletion', 'INDEX'); // Waits until the IFuture task is finished and returns its status // The calling thread is blocked while waiting Result := (FTask.Value = stLoaded); Log.Exit('Updater.WaitForCompletion', 'INDEX'); end; Log.Enter and Log.Exit are just two wrapper functions around Log.Debug that I have added to LoggerPro. The Exception occurs on the `Log.Exit` call Here are the relevant lines of the Eurekalog report: EMonitorLockException Object lock not owned. |005B7380|Application.exe|ThreadSafeQueueU.pas |{ThreadSafeQueueU}TThreadSafeQueue<LoggerPro |TLogItem>.Enqueue |157[0] | |005B61B5|Application.exe|LoggerPro.pas |TLogWriter |Log |557[5] | |0110346B|Application.exe|System.Generics.Defaults.pas | | |39[0] | |010FF5A2|Application.exe|Update.Index.pas |TUpdater |WaitForCompletion |845[4] | |010FF560|Application.exe|Update.Index.pas |TUpdater |WaitForCompletion |841[0] | Normally the update task takes some time, so the typical log output is: 2022-04-21 15:22:13:937 [TID 16780][INFO ] [INDEX ] Updater.Update in: C:\Users\Public\Documents\##### 2022-04-21 15:22:13:937 [TID 16780][DEBUG ] [INDEX ] --> Updater.StopUpdate 2022-04-21 15:22:13:937 [TID 16780][DEBUG ] [INDEX ] <-- Updater.StopUpdate 2022-04-21 15:22:13:987 [TID 16780][INFO ] [INDEX ] Contains 240 Files 2022-04-21 15:22:13:987 [TID 16780][INFO ] [INDEX ] Contains 4931 Entries 2022-04-21 15:22:13:987 [TID 3280][DEBUG ] [INDEX ] Renewing Index 2022-04-21 15:22:13:987 [TID 16780][DEBUG ] [INDEX ] --> Updater.WaitForCompletion 2022-04-21 15:22:14:080 [TID 3280][INFO ] [INDEX ] Remove 0 Files 2022-04-21 15:22:14:080 [TID 3280][INFO ] [INDEX ] Check 238 xxx Files 2022-04-21 15:22:14:080 [TID 3280][INFO ] [INDEX ] Check 2 yyy Files 2022-04-21 15:22:14:242 [TID 3280][INFO ] [INDEX ] Contains 240 Files 2022-04-21 15:22:14:242 [TID 3280][INFO ] [INDEX ] Contains 4931 Entries 2022-04-21 15:22:14:242 [TID 3280][DEBUG ] [INDEX ] Updater.Status - stLoaded 2022-04-21 15:22:14:242 [TID 16780][DEBUG ] [INDEX ] <-- Updater.WaitForCompletion ... Normal work continues here In some cases (no search paths defined or search paths empty), there's "nothing" to do, which results in the following log output: 2022-04-21 14:18:14:972 [TID 22208][INFO ] [INDEX ] Updater.Update in: C:\Users\Public\Documents\##### 2022-04-21 14:18:14:972 [TID 22208][DEBUG ] [INDEX ] --> Updater.StopUpdate 2022-04-21 14:18:14:972 [TID 22208][DEBUG ] [INDEX ] <-- Updater.StopUpdate 2022-04-21 14:18:14:973 [TID 22208][INFO ] [INDEX ] Contains 0 Files 2022-04-21 14:18:14:973 [TID 22208][INFO ] [INDEX ] Contains 0 Entries 2022-04-21 14:18:14:974 [TID 14984][DEBUG ] [INDEX ] Renewing Index 2022-04-21 14:18:14:974 [TID 14984][INFO ] [INDEX ] Remove 0 Files 2022-04-21 14:18:14:974 [TID 14984][INFO ] [INDEX ] Check 0 xxx Files 2022-04-21 14:18:14:974 [TID 14984][INFO ] [INDEX ] Check 0 yyy Files 2022-04-21 14:18:14:977 [TID 14984][INFO ] [INDEX ] Contains 0 Files 2022-04-21 14:18:14:977 [TID 14984][INFO ] [INDEX ] Contains 0 Entries 2022-04-21 14:18:14:977 [TID 14984][DEBUG ] [INDEX ] Updater.Status - stLoaded 2022-04-21 14:18:14:979 [TID 22208][DEBUG ] [INDEX ] --> Updater.WaitForCompletion 2022-04-21 14:18:14:979 [TID 22208][DEBUG ] [INDEX ] <-- Updater.WaitForCompletion ... Normal work continues here Note that in this case the updater was finished (stLoaded) before WaitForCompletion was called. The Log.Enter "--> Updater.WaitforCompletion" line may occur anywhere between the lines of the background thread (TID 14984 in this case). This is the LoggerPro output matching the bug report. The `EMonitorLockException` occured on the `Log.Exit` call in `TUpdater.WaitForCompletion` and this line is missing from the log: 2022-04-21 14:42:03:003 [TID 20620][INFO ] [INDEX ] Updater.Update in: C:\Users\Public\Documents\##### 2022-04-21 14:42:03:003 [TID 20620][DEBUG ] [INDEX ] --> Updater.StopUpdate 2022-04-21 14:42:03:003 [TID 20620][DEBUG ] [INDEX ] <-- Updater.StopUpdate 2022-04-21 14:42:03:004 [TID 20620][INFO ] [INDEX ] Contains 0 Files 2022-04-21 14:42:03:004 [TID 20620][INFO ] [INDEX ] Contains 0 Entries 2022-04-21 14:42:03:004 [TID 3312][DEBUG ] [INDEX ] Renewing Index 2022-04-21 14:42:03:004 [TID 3312][INFO ] [INDEX ] Remove 0 Files 2022-04-21 14:42:03:004 [TID 3312][INFO ] [INDEX ] Check 0 xxx Files 2022-04-21 14:42:03:004 [TID 3312][INFO ] [INDEX ] Check 0 yyy Files 2022-04-21 14:42:03:008 [TID 20620][DEBUG ] [INDEX ] --> Updater.WaitForCompletion 2022-04-21 14:42:03:008 [TID 3312][INFO ] [INDEX ] Contains 0 Files 2022-04-21 14:42:03:008 [TID 3312][INFO ] [INDEX ] Contains 0 Entries 2022-04-21 14:42:03:008 [TID 3312][DEBUG ] [INDEX ] Updater.Status - stLoaded ... Normal work continues here Note that the updater was still working (on nothing ;-)) when WaitForCompletion was called. It looks like Log.Exit('WaitForCompletion') and Log.Debug('Updater.Status - stLoaded') happen in the same millisecond, so I assume that thread 3312 still held the lock, when exception thread 20620 called `Log.Exit`. But I see this all the time (finish/exit happens in the sme millisecond) when I run the code on my PC and never get an EMonitorLock exception. Is there something we are doing wrong or have we come across a race condition in LoggerPro or the Delphi locking implementation?
  5. Apart from the obvious "length", "height" and "weight", I tend to mistype phonetically similar consonants. E.g. "t/d", "b/v" like "wader" instead of "water".
  6. luebbe

    Delphi profiler

    @FPiette do you know https://github.com/neslib/Neslib.Xml? I switched some of my xml parsing from Delphi's native parser to Neslib.Xml and it resulted in around 35x-40x faster parsing (17-20 seconds versus <= 0.5 seconds).
  7. luebbe

    Howto prevent a grid from scrolling

    Sorry no, it doesn't help. The stringgrid still catches all mouse wheel events. And there is a stack overflow in TControl.Defaulthandler when I'm not over a grid.
  8. luebbe

    Howto prevent a grid from scrolling

    Hi Folks, I'm stuck with the problem that I want to prevent a grid to act on the mouse wheel events. The UI layout is the following: On a TFrame (created at runtime) I have a TCategoryPanelGroup. As the application is receiving data in different formats, for each data package a new TCategoryPanel is created at runtime and placed on the TCategoryPanelGroup. Each TCategoryPanel contains two grids who are adjusted to fit the data. The heights of the grids and the TCategoryPanel are adjusted so that in >90% of the cases the grids won't have a scrollbar. Now when I use the mouse wheel over a grid, the grid catches the wheel and happily acts on it, which is not what I want. If the grid has a scrollbar (rare case), the user shall use the scrollbar to scroll the grid. My goal is to always scroll the TCategroyPanelGroup when the mouse wheel is used over one of the grids or a TCategorypanel so the user can quickly flip through the categories. How can I make the grids and the TCategoryPanel "ignore" or "pass up" the mouse wheel events so that the TCategoryPanelGroup receives them and can act on them? Would a different structure of UI elements be a better approach? I'm actually quite happy with the category panels, because the data inside can be clearly identified via their header and they can be collapsed when I don't want to see all different data sets at the same time. I've attached a stripped example of the UI structure that just catches the mouse wheel events for the controls and outputs them in a memo. MouseScroll.zip
  9. luebbe

    Google Charts in uniGUI

    Looks nice. I'm missing information on where to find unigui. A search on GitHub resulted in a lot of hits.
  10. luebbe

    The state of GExperts Support for Delphi 11

    Probably a rounding problem? @pyscripter has created a dpi aware base form which IIRC uses muldiv to adjust to dpi changes. Enjoy your vacation!
  11. not 4K, but two monitors with different resolutions HD and WQHD. Setting one of them to a scaling >100% screws up a lot of things in and around the IDE.
  12. luebbe

    C++ Code Insight in 10.4.2

    @Lajos Juhász Did you notice that the link that you posted actually goes through facebook?
  13. Thanks Stefan, in the debugger I saw in ItemCallback(..) that the addresses of FItem and AItem were similar but not equal, so I suspected that there was something wrong with the interface being passed around instead of the object. I put a breakpoint on the first line of procedure TestIntfItem.ItemCallback(AItem: IMyIntfItem); begin Assert.IsNotNull(AItem); FCallbackResult := AItem.Caption; end; with TOnMyIntfItemSelected<T: IMyIntfItem> = procedure(AItem: T) of object; I see: Name Wert Self (TMyIntfItemA<List.Intf.IMyIntfItem>($3AA2840) as IMyIntfItem, '') AItem Pointer($3AA2828) as IMyIntfItem This told me that something was wrong, but I couldn't understand what. with TOnMyIntfItemSelected<T: IMyIntfItem> = procedure(AItem: IMyIntfItem) of object; I see: Name Wert Self (TMyIntfItemA<List.Intf.IMyIntfItem>($3AC38D8) as IMyIntfItem, '') AItem TMyIntfItemA<List.Intf.IMyIntfItem>($3AC38D8) as IMyIntfItem That's an evil trap. Thanks for shedding light on it. So if something is wrong I have to watch out for $18 byte address offsets 😉
  14. Back from vacation... Thanks for further feedback, I probably oversimplified the interface in order to produce a minimal example. In fact I do have stuff in the interface. The attached project contains two different implementations, one interface based and one skeleton based, with a few unit tests. You need TestInsight installed and the path to DUnitX in the $(DUNITX) variable to run it. I needed a callback for a list item (selection) and for the list itself (changed). The skeleton based implementation works as expected, but the interface based callback for the list item fails with an A/V and I don't understand why. I'm probably still doing something wrong with the generic definition. Could someone please enlighten me what my mistake is? Project4.zip
  15. Meanwhile I prefer interfaces over abstract classes. It was the other way round 20 years ago. Still struggling with the data passed in the callback, but I'll look into it again ten days from now. Finally a bit of vacation 🙂
×