Moving beyond Clarion 10 11897 (Cross-Thread Deadlock Silent GPF's)

Tags: #<Tag:0x00007f60c10a2a70>


Back in September 2017 I first put into production an application that worked fine with C10 11897, but with C10 12799 would occasionally (as in maybe once a week, or 5 times in a day) give silent gpf’s on certain workstations running Windows 7 or Windows 10. Usually I would see a Cross-Thread Deadlock show up in the Windows Event Viewer for the hang. I rolled-back to C10 11897 and no problems. I shelved the issue for the time being, but then in June 2018 decided to track this down. It is something that I could never reproduce at will, but some sites had it more often than others.

I figured it was a global variable issue, so I made sure all of mine were updated with a critical section. Using DebugView and the Clarion debug runtime dll and Capesoft’s GPF reporter I got lots of data with line numbers and such, but no smoking gun. Fortunately, I had a customer site where I could load test versions on two of their computers, run DebugView, and use TeamViewer to record their 12-hour sessions, so I could replay what they were doing when a crash occurred. For all the logs generated, I only got one place in my code that I could fix, but the other crashes were happening when different procedures would exit (i.e. ThisWindow.Kill). Different procedures, different threads referenced for the crashes that would occur at various places in the program.

This is a standard ABC MDI app. I had put in the Faux Max template a while back, and that did help reduce the frequency of the crashes (by eliminating a window being maximized), but it didn’t fix things 100%. In fact quite by accident I saw in reviewing a TeamViewer session a workstation which still maximized a browse window since it had saved that window setting on the workstation before getting the updated program with FauxMax in it, and that would lead to a crash such that I was able to reproduce it myself. Eliminating the saved maximize setting in the ini file fixed the crash for that browse, but still the silent gpf’s persisted in other parts of the program.

I had seen a discussion in the Clarion chat group last summer about converting an MDI app to SDI, which fixed for the user a lot of weird lockups in a heavily-threaded app. The user wrote he had a template change which used the second form of Open(Window) to supply the parent (owner) window to get around possible situations where (say) an update form might appear behind its parent browse, but I was concerned it would take a lot of testing for my app, so I saved that one for another day. But 9 months later, I had run out of ideas, and decided to go for it. But I didn’t do a complete switch-over–I left the main frame (application) MDI, but changed all child windows to be SDI by removing the MDI attribute. My theory was since Microsoft has written that MDI is deprecated and and not thread-safe, if I kept the MDI usage to a single thread then I wouldn’t have any cross-thread issues. Doing it this way I still have the same behavior I did before without worrying about using open window with an owner–no update forms are being covered-up by their parent browses.

So anyway, I’m happy to report that during my last 12-hour session, I had no lockups on my two test computers (where before I would have at least 5 between the two of them on any given day) and the users didn’t even notice any changes. Of course now windows can be maximized since they are SDI (FauxMax only works on MDI windows), but since it was only MDI windows that have the maximize issue I’m fine with that. And I removed the Standard Window Top-Level Menu, since it only works with MDI windows.

These are the steps I did to convert my Child windows from MDI to SDI. Credit for all these ideas go to the chat between Peter Petropoulos, Owen Brunker, Mark Goldberg, Dennis Evans, and Bruce Johnson in CW-Talk back on June 19, 2018.

Steps to remove all MDI attributes from child windows (while leaving your Main Frame an Application)

  1. Export app to txa.

  2. Edit txa.

  3. Search and replace:
    with nothing (case-sensitive).

  4. Search and replace:
    with nothing (case-sensitive). This one takes care of continued lines.

  5. Search and replace:
    %WindowOperationMode DEFAULT (‘MDI’)
    %WindowOperationMode DEFAULT (‘Use WINDOW setting’)
    (This takes care of ABC reports that might have a progress window defaulted to MDI.)

  6. Save txa.

  7. Recreate app from this newly-saved txa (New Solution, Project, or Application–Application from Txa) I recreate it with the same filename with the app’s solution open but the app closed so it overwrites the existing app file, just don’t let it overwrite the appname.cwproj file.

  8. Recompile and test.