Non deterministic wooden table based window message posting



  •  Since I see that there are a couple of Delphi devs here, it's about time I shared a great WTF from back when I was a Delphi coder.

     You all know how careful you have to be when creating multithreaded applications.My colleague was aware of the dangers but knew just how to take care of them: protect the thread's entire code in a call to Synchronize!

    The code (recalled from memory, forgive any mistakes!) looks like this:

     

    TWTFThread=class(TThread)

        procedure Execute(); override;

        procedure DoWork();

    end;

     

    procedure TWTFThread.Execute()

    begin

        Synchronize(DoWork);

    end;

     

    procedure TWTFThread.DoWork()

    begin

        //thread code goes here instead of execute.

    end;

    Delphi programmers will appreciate the WTF. I'll explain it for those that don't know Delphi. The Execute procedure is the entry point for the thread. The Synchronize method (inherited from your thread's base class) takes a method as a parameter and executes the provided method in the main thread. It sort of interrupts the main thread (in reality it posts a window message to the main thread's queue) and has it execute the method, the Synchronize call waits for the main thread to finish executing the main thread before returning.

    The questionable idea behind Synchronize is that you can still use code which isn't thread safe from your thread. Almost the entire VCL library (Delphi's runtime) is not thread safe, it can only be used from the main thread. So you can change a button's text from a thread by ensuring that the method which sets the button's text is in a Synchronize protected method. Nevermind that whole send-the-main-thread-a-message-when-its-finished idea, heh.

    Back to the WTF. What this means is that my colleague's code creates a thread, and then the thread immediately switches back to the main thread in order to avoid all the difficulties of creating safe multithreaded code.

    But I have yet to reach the end of this foul tale! The way he created the thread was equally bizzare.

     Instead of just creating a TWTFThread instance, he would post a custom window message to his window, and then immediately dispatch the message with a Application.ProcessMessages call. The handler for the window message would then create the TWTFThread object (and as explained, the thread would join back into the main thread!). Oh, and the handler for his custom window message wasn't done as a message method, he would chain the Application object's OnMessage event. Code looks like this:

     

    const WM_START_WTF_THREAD = WM_USER+2;

     

    procedure TWTFForm.DoSomeShitAndStartWTFThread();

    begin

       {...}

       PostMessage(Handle,WM_START_WTF_THREAD,0,0);

       Application.ProcessMessages;

       {...}

    end;

     

    procedure TWTFForm.HookedApplicationObjectOnMessageHandler() {I forget the arguments to this}

    begin

      {...}

       If Msg=WM_START_WTF_THREAD then

          TWTFThread.Create();

      { Call the previous OnMessage handler }

     {...}

    end;

     

    Those of  you able to follow the sequence of events will realise that this amounts to no more than simply posting a custom message to one's self and then servicing it during idle time. This is because the message sent by Synchronize will likely only be serviced during the main thread's idle time. Maybe, depends if the scheduler switches to the WTF thread before DoSomeShitAndStartWTFThread's ProcessMessages call returns.

    I quizzed my colleague about this and he was defensive and rather proud of his ingenious turnkey solution to making thread safe code. It was thread safe as far as he was concerned, so he wouldn't acknowledge the idea of changing it. I just can't begin to imagine being that dumb or self delusional. A mighty "HA!" you you fools who bothered learning about "semaphores", "mutual exclusion", "deadlocks" and "dining philosophers". Why bother with all that when you can just go around the problem.

     



  • I wish I could say, "My, what a novel and previously unheard of WTF."

    Unfortunately, I've caught three programs basically doing this kind of a trick so far this year.  One of them even opened up a hidden window for each of the "thread"s.



  • There was a lot of that kind of thing going on at the Delphi shop where I worked. That place also made heavy use of window messages to facilitate event driven programming.



  • I guess it is thread-safe, although I'd prefer to call this approach thread-imperial.  No matter where you run it from, it will always take control of your message queue.

    Also, starting messages at WM_USER in Delphi is a no-no.  The VCL uses everything in the range of WM_USER to WM_APP.

    If you want some real fun, try starting a TWTFThread and then immediately WaitFor() it.  Your colleague will have hours of fun trying to debug that race condition.



  • Speaking of wooden tables:

    > http://zuguttenberg.de/index.php?url=http://img232.exs.cx/img232/1552/otf2za.jpg

    This guy has just become the new German finance minister. 

     EDIT: Hm, at least he seems to have plugged that XSS-hole. Well, we have a screenshot:

    > http://img155.imageshack.us/img155/9107/mlekob3.jpg



  • @agtrier said:

    This guy has just become the new German finance minister.

    Man, really?


    I'm totally not aware of what's happening around me. If Berlin was destroyed in a terrorist attack, I guess I'ld hear about that a few days later on TDWTF for some... odd reason.



  • @agtrier said:

    Speaking of wooden tables:

    > http://zuguttenberg.de/index.php?url=http://img232.exs.cx/img232/1552/otf2za.jpg

    This guy has just become the new German finance minister. 

     EDIT: Hm, at least he seems to have plugged that XSS-hole. Well, we have a screenshot:

    > http://img155.imageshack.us/img155/9107/mlekob3.jpg

    You keep making those non-link links. Plaese stop and make link links.



  • @Spectre said:

    You keep making those non-link links. Plaese stop and make link links.

    You keep making non-sense sense.  Please stop and make sense sense.



  • @Chuck Mango said:

    Delphi programmers will appreciate the WTF. I'll explain it for those that don't know Delphi.

    Thank you! Thank you! Thank you! For taking the time to actually explain what the WTF is and not just assuming that every developer knows the language you're posting in.  I like a good story, not a Where's Waldo book.  Thanks again.



  • @Aaron said:

    Also, starting messages at WM_USER in Delphi is a no-no.  The VCL uses everything in the range of WM_USER to WM_APP.
     

    Really? I don't remember reading anything in the Delphi docs about which ranges of messages were off limits. Could you easily cite something to confirm that? I honestly did try and Google it myself but didn't easily find anything. Don't sweat it you can't easily cite anything, I'm not a Delphi dev anymore and hence I am only curious. I seem to remember the VCL using the upper part of the message ranges, maybe I'm wrong.

     @Aaron said:

    If you want some real fun, try starting a TWTFThread and then immediately WaitFor() it.

     I'm not laughing!! There really was a deadlock condition quite similar to that in the code :) I also found a deadlock risk in Synchronize itself (in Delphi 6 at least).

    @Aaron said:

    Your colleague will have hours of fun trying to debug that race condition.

    You can tell I have more fabulous stories to share...



  • @Spectre said:

    @agtrier said:

    Speaking of wooden tables:

    > http://zuguttenberg.de/index.php?url=http://img232.exs.cx/img232/1552/otf2za.jpg

    This guy has just become the new German finance minister. 

     EDIT: Hm, at least he seems to have plugged that XSS-hole. Well, we have a screenshot:

    > http://img155.imageshack.us/img155/9107/mlekob3.jpg

    You keep making those non-link links. Plaese stop and make link links.

     

    Well, how? This grizzly ol' ex Usenet froup trolle would like to know too.

    inb4RTFM.


Log in to reply