Thread: Reentrant Message Processing (WndProc)

  1. #1
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108

    Reentrant Message Processing (WndProc)

    I hate the WIN##API. I'm getting so much conflicting data that I have no choice other than asking.

    I'll save you most of the life story, but I'll post some source if my question/explanation isn't clear enough.

    The question: is there some magic to the Windows OS message queuing implementation that prevents race conditions?

    My understanding is that `WndProc' must be reentrant. You must code under the assumption that basically any message may start processing while basically any message is processing.

    Much of the evidence I've found suggests that it is magic. (The evidence being all the readily available source that transforms shared state without any sort of synchronization as part of processing user defined messages (`WM_USER'). I'm not just talking about example programs either.)

    Forgive the naïve question, but I'm pulling out some of my old stuff for an open source project and I can only imagine that it will randomly crash depending on the phases of the moon. (I didn't do any synchronization for several messages that seem very likely to process "at the same time".)

    Soma

  2. #2
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    There are really only two ways that the Window Procedure can be invoked: 'indirectly', from the thread running the message pump (conceptually originating from a PostMessage call), and 'directly', via some SendMessage call. It's the latter that really demands reentrance. For example, if you call SetWindowText from the Window Procedure, it actually translates to a SendMessage call (with the WM_SETTEXT message id) which is processed immediately. In either case, though, both types of calls are guaranteed to take place in the main thread (unless of course there are multiple threads in your program).

    [edit]
    Now that I think of it, there is a third way, via the PostThreadMessage API. But it still executes in the message pump thread...

    >> I'll post some source if my question/explanation isn't clear enough.

    Just out of curiosity, would you mind posting it?
    [/edit]
    Last edited by Sebastiani; 04-27-2009 at 10:05 PM.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  3. #3
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    And... how does that answer my question? O_o

    Soma

  4. #4
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Explain "race condition" in the context of a single-threaded message pump.

    gg

  5. #5
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    My response was based on the (perhaps erroneous) assumption that you were talking about a single-threaded application (it's a common misconception that Windows passes messages asyncronously within an application). But the short answer is no, the Windows subsystem does not make any provisions for preventing race conditions in multithreaded applications.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  6. #6
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    "Explain "race condition" in the context of a single-threaded message pump."

    I'm not talking about the message pump. I'm not talking about the function that processes the messages.

    "common misconception that Windows passes messages asyncronously within an application"

    Presumably you mean "within a single threaded application"? O_o

    "But the short answer is no, the Windows [...] applications."

    I'm really not getting these references to single threaded versus multiple thread contexts. I specifically mention race conditions and all windows in the system have the potential to be called from an outside thread or outside processes regardless of how the original client may have been written.

    Stay with me for an example...

    a.exe:
    Code:
    SendMessage(b.exe::hwnd, WM_WHATEVER, PARAM1, 0);
    SendMessage(b.exe::hwnd, WM_WHATEVER, PARAM2, 0);
    b.exe:
    Code:
    case WHATEVER:
    //??? process state
    ReplyMessage(0);
    //??? process state
    My understanding is that `SendMessage' posts a message to the queue if the call originates from a different thread. Now with a single threaded "b.exe" I can see how this wouldn't be a problem if and only if `DispatchMessage' waits until the message is processed. (If it returns before the message is processed another `GetMessage' plus `DispatchMessage' cycle may complete before the message is processed and after the second message is posted.)

    Further, my understanding is that `SendMessage' basically just functions as a direct call to `WndProc' if originating from the same thread. With that in mind, I simply can't imagine what protections may have been in place to prevent race conditions within a multiple threaded application.

    Now, I'm giving myself a leave because I hate the API and like pretend it doesn't exist. That doesn't really explain the various who call themselves "Windows® Programmers"--'R' and all--who, in my understanding, have basically guaranteed that their source will fail in any situation similar to the above. I want to know if this is some aspect of the message queuing facility I simply don't understand or if these individuals just didn't bother to deal with the potentially damaging lack of synchronization.

    Soma

  7. #7
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> My understanding is that `SendMessage' posts a message to the queue if the call originates from a different thread. Now with a single threaded "b.exe" I can see how this wouldn't be a problem if and only if `DispatchMessage' waits until the message is processed.

    That is correct.

    >> Further, my understanding is that `SendMessage' basically just functions as a direct call to `WndProc' if originating from the same thread. With that in mind, I simply can't imagine what protections may have been in place to prevent race conditions within a multiple threaded application.

    Windows makes no attempts whatsoever (or at least it certainly doesn't guarantee to do so) to prevent race conditions in your application. The only way you're going to avoid them is by using synchonization objects. Period.

    >> I want to know if this is some aspect of the message queuing facility I simply don't understand or if these individuals just didn't bother to deal with the potentially damaging lack of synchronization.

    Irrespective of the operating system, it's pretty much a given that synchronization is the sole responsibility of the programmer. As long as you keep that in mind, you should be fine (besides deadlocks and such, of course, which is a totally different matter).
    Last edited by Sebastiani; 04-28-2009 at 10:33 AM. Reason: for mat ting
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  8. #8
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> and all windows in the system have the potential to be called from an outside thread or outside processes
    Not directly. Message dispatching is done within the context of the thread that created/owns the message Q. No synchronization is required, unless you're calling the window procedure directly from another thread of course.

    More reading on message routing/handling in the context of multiple threads/processes:
    msdn.microsoft.com/en-us/library/ms644927(VS.85).aspx#routing

    Also see Remarks for SendMessage:
    msdn.microsoft.com/en-us/library/ms644950(VS.85).aspx

    gg

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Strange string behavior
    By jcafaro10 in forum C Programming
    Replies: 2
    Last Post: 04-07-2009, 07:38 PM
  2. Message class ** Need help befor 12am tonight**
    By TransformedBG in forum C++ Programming
    Replies: 1
    Last Post: 11-29-2006, 11:03 PM
  3. Dialog Box Problems
    By Morgul in forum Windows Programming
    Replies: 21
    Last Post: 05-31-2005, 05:48 PM
  4. Tab Controls - API
    By -KEN- in forum Windows Programming
    Replies: 7
    Last Post: 06-02-2002, 09:44 AM