Safe to create wx gui objects in a non-gui thread?

We've got multiple threads in our application, the gui thread and worker threads. A worker thread wants to display a modal dialog. I've read on this list that you can't call a wx gui function in a non-gui thread. But is it safe to create a wx MessageDialog in a worker thread, pass it to the gui thread and let the gui thread call ShowModal(), using a Python semaphore to block the worker thread until the result is available?

If it isn't, is there a recommended way to accomplish this?

Thanks. -Steven.

Hi Steven,

···

On Tue, Aug 19, 2008 at 3:21 PM, Steven Watanabe Steven.Watanabe@autodesk.com wrote:

We’ve got multiple threads in our application, the gui thread and worker threads. A worker thread wants to display a modal dialog. I’ve read on this list that you can’t call a wx gui function in a non-gui thread. But is it safe to create a wx MessageDialog in a worker thread, pass it to the gui thread and let the gui thread call ShowModal(), using a Python semaphore to block the worker thread until the result is available?

If it isn’t, is there a recommended way to accomplish this?

I don’t know if there’s a recommended way to accomplish this. Here’s copy-paste from a piece of my code:


class AskPasswordDialog(AskPasswordDialogBase):

def ask_for_username_password(self, realm, uri):
    """Ask for username / password. This code can be called from another
       thread than the GUI thread!"""
   

    wx.CallAfter(self.enter_passwd_prompt.SetValue, self.PWD_PROMPT % (realm, uri))
   
    from threading import Event
   
    enterPwdEvent = Event()
    enterPwdEvent.clear()

   
    # This method will run in the GUI thread
    def ask_password_handler():
        if self.ShowModal():
            enterPwdEvent.uname_pwd = self.text_username.GetValue(), self.text_password.GetValue()

        else:
            enterPwdEvent.uname_pwd = (None, None)
        enterPwdEvent.set()
        return
   
    wx.CallAfter(ask_password_handler)
    enterPwdEvent.wait()

    return enterPwdEvent.uname_pwd

The method ‘ask_for_username_password()’ is a method on the dialog which I want to show; in my case the dialog is already pre-created and my worker-thread calls that method. I can safely do this, because it’s my own method, not a wxWidgets method. However, you don’t have to do it that way.

The import points here are:

  • From the Worker Thread create an Event object, imported from module threading
  • have a seperate method that creates your dialog, shows it, gets the value from the user, etc.
  • This method must have access to the Event object! Either as parameter, or you can create it as a nested method as I’ve done here.
  • When you’re finished with the GUI stuff in your GUI-method, set properties on the Event object and call the ‘set()’ method on it.
  • From the Worker Thread, use wx.CallAfter() to start your GUI stuff.
  • Right after that, call method ‘wait()’ on the Event object
  • When wait() returns, you have the results from your GUI-call.
  • The results are available in the Event object, b/c you set them as extra properties there from your GUI stuff method.

Success,

–Tim

Thanks. -Steven.


wxpython-users mailing list

wxpython-users@lists.wxwidgets.org

http://lists.wxwidgets.org/mailman/listinfo/wxpython-users

Steven Watanabe wrote:

We've got multiple threads in our application, the gui thread and worker threads. A worker thread wants to display a modal dialog. I've read on this list that you can't call a wx gui function in a non-gui thread. But is it safe to create a wx MessageDialog in a worker thread, pass it to the gui thread and let the gui thread call ShowModal(), using a Python semaphore to block the worker thread until the result is available?

If it isn't, is there a recommended way to accomplish this?

Thanks. -Steven.

I would just pass a message to the gui-thread that you want it to show a dialog using wx.CallAfter (which is thread-safe) and pubsub (which isn't).

···

-------------------
Mike Driscoll

Blog: http://blog.pythonlibrary.org
Python Extension Building Network: http://www.pythonlibrary.org

Steven Watanabe wrote:

We’ve got multiple threads in our application, the gui thread and worker threads. A worker thread wants to display a modal dialog. I’ve read on this list that you can’t call a wx gui function in a non-gui thread. But is it safe to create a wx MessageDialog in a worker thread, pass it to the gui thread and let the gui thread call ShowModal(), using a Python semaphore to block the worker thread until the result is available?

If it isn’t, is there a recommended way to accomplish this?

Thanks. -Steven.

I would just pass a message to the gui-thread that you want it to show a dialog using wx.CallAfter (which is thread-safe) and pubsub (which isn’t).

Well, but then how to get an answer back from the GUI thread, back to the Worker thread? That’s what I solved, for my program, using the Event() object and setting extra properties on that Event object.

The Worker Thread waits until the GUI thread calls event.set(), and then reads out the results from the Event object.

Regards,

–Tim

···

On Tue, Aug 19, 2008 at 4:44 PM, Mike Driscoll mike@pythonlibrary.org wrote:


Mike Driscoll

Tim van der Leeuw wrote:

    Steven Watanabe wrote:

        We've got multiple threads in our application, the gui thread
        and worker threads. A worker thread wants to display a modal
        dialog. I've read on this list that you can't call a wx gui
        function in a non-gui thread. But is it safe to create a wx
        MessageDialog in a worker thread, pass it to the gui thread
        and let the gui thread call ShowModal(), using a Python
        semaphore to block the worker thread until the result is
        available?

        If it isn't, is there a recommended way to accomplish this?

        Thanks. -Steven.

    I would just pass a message to the gui-thread that you want it to
    show a dialog using wx.CallAfter (which is thread-safe) and pubsub
    (which isn't).

Well, but then how to get an answer back from the GUI thread, back to the Worker thread? That's what I solved, for my program, using the Event() object and setting extra properties on that Event object.

The Worker Thread waits until the GUI thread calls event.set(), and then reads out the results from the Event object.

Regards,

--Tim

This was more of a shot in the dark than anything. However, since pubsub isn't technically just for wx, you should be able to set up a receiver in any of your threads and just publish to them, probably using the wx.CallAfter method. So you could post a message to the main GUI and have it do it's thing, then it could post a message back, so to speak. Hopefully Josiah or the pubsub creator can give both of us a clue.

Mike

···

On Tue, Aug 19, 2008 at 4:44 PM, Mike Driscoll <mike@pythonlibrary.org > <mailto:mike@pythonlibrary.org>> wrote:

Tim van der Leeuw wrote:

Steven Watanabe wrote:



    We've got multiple threads in our application, the gui thread

    and worker threads. A worker thread wants to display a modal

    dialog. I've read on this list that you can't call a wx gui

    function in a non-gui thread. But is it safe to create a wx

    MessageDialog in a worker thread, pass it to the gui thread

    and let the gui thread call ShowModal(), using a Python

    semaphore to block the worker thread until the result is

    available?



    If it isn't, is there a recommended way to accomplish this?



    Thanks. -Steven.



    



I would just pass a message to the gui-thread that you want it to

show a dialog using wx.CallAfter (which is thread-safe) and pubsub

(which isn't).

Well, but then how to get an answer back from the GUI thread, back to the Worker thread? That’s what I solved, for my program, using the Event() object and setting extra properties on that Event object.

The Worker Thread waits until the GUI thread calls event.set(), and then reads out the results from the Event object.

Regards,

–Tim

This was more of a shot in the dark than anything. However, since pubsub isn’t technically just for wx, you should be able to set up a receiver in any of your threads and just publish to them, probably using the wx.CallAfter method. So you could post a message to the main GUI and have it do it’s thing, then it could post a message back, so to speak. Hopefully Josiah or the pubsub creator can give both of us a clue.

Hi Mike,

I don’t use pubsub myself so my solutions to questions here tend not to include it either :slight_smile:

I don’t know how to work with pubsub; I don’t mean to flame against it either. However, I think that messages sent with pubsub get processed on the same thread as they are sent. I believe that the receivers of messages, in pubsub framework, don’t have limitations on the use of GUI. That would mean you can not send a message to another thread, unless this is an option somewhere. The Worker thread can send a message to a topic, and the subscriber to the topic will pick it up, but processing will then happen all in the same thread.

If the use of multiple threads for pubsub is an option which can be activated somewhere, then there’s still the problem that the Worker thread needs to wait for the GUI thread to give it back an answer, and however you arrange communication between Worker and GUI thread (wx.CallAfter, messaging, pubsub), this is a problem which at the fundamental level is solved by things like the Python threading.Event object, semaphores, locks, and such.

One can build synchronous request-reply messaging models on top of that, and perhaps one could even build that on top of pubsub, but my understanding is that pubsub is not designed for such request-reply type of communication. There is 1 publisher and 0-many subscribers. So if the Worker thread would enter a wait-state, waiting for pubsub to give it a message on the designated return-topic, it has no guarantee that there’s a subscriber to catch it’s message, or that there are perhaps multiple subscribers who each try to respond.

Sure, you can always give those guarantees in your code and the threading.Event has the same problem: I’m trying to point out where the conceptual mismatch is.

Hey, I hope that I haven’t gone too far overboard on the theory, and that I’m not misjudging pubsub too much! I don’t mean to flame, I don’t mean this as a diatribe - sometimes I sound that way without meaning to.

I see that pubsub is good for many things and that I could myself use it in many situations where I currently don’t (binding with events instead), but I don’t think that the use of pubsub is applicable here in the use-case where a background Worker Thread needs to make a request to the GUI Thread, and also needs to wait for an answer.

Mike

Regards,

–Tim :slight_smile:

···

On Tue, Aug 19, 2008 at 7:00 PM, Mike Driscoll mike@pythonlibrary.org wrote:

On Tue, Aug 19, 2008 at 4:44 PM, Mike Driscoll <mike@pythonlibrary.org mailto:mike@pythonlibrary.org> wrote:

Tim van der Leeuw wrote:

    Tim van der Leeuw wrote:

           Steven Watanabe wrote:

               We've got multiple threads in our application, the gui
        thread
               and worker threads. A worker thread wants to display a
        modal
               dialog. I've read on this list that you can't call a wx gui
               function in a non-gui thread. But is it safe to create a wx
               MessageDialog in a worker thread, pass it to the gui thread
               and let the gui thread call ShowModal(), using a Python
               semaphore to block the worker thread until the result is
               available?

               If it isn't, is there a recommended way to accomplish this?

               Thanks. -Steven.

           I would just pass a message to the gui-thread that you want
        it to
           show a dialog using wx.CallAfter (which is thread-safe) and
        pubsub
           (which isn't).

        Well, but then how to get an answer back from the GUI thread,
        back to the Worker thread? That's what I solved, for my
        program, using the Event() object and setting extra properties
        on that Event object.

        The Worker Thread waits until the GUI thread calls
        event.set(), and then reads out the results from the Event object.

        Regards,

        --Tim
         
    This was more of a shot in the dark than anything. However, since
    pubsub isn't technically just for wx, you should be able to set up
    a receiver in any of your threads and just publish to them,
    probably using the wx.CallAfter method. So you could post a
    message to the main GUI and have it do it's thing, then it could
    post a message back, so to speak. Hopefully Josiah or the pubsub
    creator can give both of us a clue.

Hi Mike,

I don't use pubsub myself so my solutions to questions here tend not to include it either :slight_smile:

I don't know how to work with pubsub; I don't mean to flame against it either. However, I think that messages sent with pubsub get processed on the same thread as they are sent. I believe that the receivers of messages, in pubsub framework, don't have limitations on the use of GUI. That would mean you can not send a message to another thread, unless this is an option somewhere. The Worker thread can send a message to a topic, and the subscriber to the topic will pick it up, but processing will then happen all in the same thread.

If the use of multiple threads for pubsub is an option which can be activated somewhere, then there's still the problem that the Worker thread needs to wait for the GUI thread to give it back an answer, and however you arrange communication between Worker and GUI thread (wx.CallAfter, messaging, pubsub), this is a problem which at the fundamental level is solved by things like the Python threading.Event object, semaphores, locks, and such.
One can build synchronous request-reply messaging models on top of that, and perhaps one could even build that on top of pubsub, but my understanding is that pubsub is not designed for such request-reply type of communication. There is 1 publisher and 0-many subscribers. So if the Worker thread would enter a wait-state, waiting for pubsub to give it a message on the designated return-topic, it has no guarantee that there's a subscriber to catch it's message, or that there are perhaps multiple subscribers who each try to respond.
Sure, you can always give those guarantees in your code and the threading.Event has the same problem: I'm trying to point out where the conceptual mismatch is.

Hey, I hope that I haven't gone too far overboard on the theory, and that I'm not misjudging pubsub too much! I don't mean to flame, I don't mean this as a diatribe - sometimes I sound that way without meaning to.

I see that pubsub is good for many things and that I could myself use it in many situations where I currently don't (binding with events instead), but I don't think that the use of pubsub is applicable here in the use-case where a background Worker Thread needs to make a request to the GUI Thread, and also needs to wait for an answer.

    Mike

Regards,

--Tim :slight_smile:

Tim,

Don't worry about me. I like pubsub, but don't usually make Python scripts that are complex enough to warrant its inclusion. The same is true of threads. I use them from time to time, but not enough to be very familiar with them. Threads are something I'd really like to learn better though. I did a quick Google search and found this recipe which sounds like it might work for this use-case:

http://code.activestate.com/recipes/491281/

It claims that it's "especially useful for non-blocking UI techniques and for load distribution on jerky resources"

I'll let you be the judge of that.

Mike

···

On Tue, Aug 19, 2008 at 7:00 PM, Mike Driscoll <mike@pythonlibrary.org > <mailto:mike@pythonlibrary.org>> wrote:
        On Tue, Aug 19, 2008 at 4:44 PM, Mike Driscoll > <mike@pythonlibrary.org <mailto:mike@pythonlibrary.org> > <mailto:mike@pythonlibrary.org > <mailto:mike@pythonlibrary.org>>> wrote:

Hi Mike,

Tim van der Leeuw wrote:

[…]

Tim,

Don’t worry about me. I like pubsub, but don’t usually make Python scripts that are complex enough to warrant its inclusion. The same is true of threads. I use them from time to time, but not enough to be very familiar with them. Threads are something I’d really like to learn better though. I did a quick Google search and found this recipe which sounds like it might work for this use-case:

http://code.activestate.com/recipes/491281/

It claims that it’s “especially useful for non-blocking UI techniques and for load distribution on jerky resources”

I’ll let you be the judge of that.

From the description it sounds like it would work, but I haven’t studied the sources to see if it would. I get the feeling that my solution with just threading.Event is simpler (but also less capable).

I’m considering to wrap up my code in a nice generic utility-method that could be added to wxPython under the name of wx.CallReturn(), or something like that.

Mike

Regards,

–Tim

···

On Tue, Aug 19, 2008 at 8:32 PM, Mike Driscoll mike@pythonlibrary.org wrote:

CallQueue would work, but it's just another implementation of the
worker thread pattern.

As stated previously, pubsub doesn't do anything special, so...

What I would do, because I'm generally pretty lazy, is something like
the following...

SENTINEL = object

def get_password():
    x = [None]
    def get_password(window, message, destination, caption="Enter
Password", style=wx.OK|wx.CANCEL|wx.CENTRE):
        y = wx.PasswordEntryDialog(window, message, caption, style=style)
        if y.ShowModal() == wx.ID_OK:
            destination[0] = y.GetValue()
        else:
            destination[0] = SENTINEL
        y.Destroy()
    wx.CallAfter(get_password, ROOTWINDOW, "some message", x)

    while x[0] is None:
        time.sleep(.1)
    return x[0]

- Josiah

···

On Tue, Aug 19, 2008 at 11:32 AM, Mike Driscoll <mike@pythonlibrary.org> wrote:

Tim van der Leeuw wrote:

On Tue, Aug 19, 2008 at 7:00 PM, Mike Driscoll <mike@pythonlibrary.org >> <mailto:mike@pythonlibrary.org>> wrote:

   Tim van der Leeuw wrote:

       On Tue, Aug 19, 2008 at 4:44 PM, Mike Driscoll >> <mike@pythonlibrary.org <mailto:mike@pythonlibrary.org> >> <mailto:mike@pythonlibrary.org >> <mailto:mike@pythonlibrary.org>>> wrote:

          Steven Watanabe wrote:

              We've got multiple threads in our application, the gui
       thread
              and worker threads. A worker thread wants to display a
       modal
              dialog. I've read on this list that you can't call a wx gui
              function in a non-gui thread. But is it safe to create a wx
              MessageDialog in a worker thread, pass it to the gui thread
              and let the gui thread call ShowModal(), using a Python
              semaphore to block the worker thread until the result is
              available?

              If it isn't, is there a recommended way to accomplish this?

              Thanks. -Steven.

          I would just pass a message to the gui-thread that you want
       it to
          show a dialog using wx.CallAfter (which is thread-safe) and
       pubsub
          (which isn't).

       Well, but then how to get an answer back from the GUI thread,
       back to the Worker thread? That's what I solved, for my
       program, using the Event() object and setting extra properties
       on that Event object.

       The Worker Thread waits until the GUI thread calls
       event.set(), and then reads out the results from the Event object.

       Regards,

       --Tim

   This was more of a shot in the dark than anything. However, since
   pubsub isn't technically just for wx, you should be able to set up
   a receiver in any of your threads and just publish to them,
   probably using the wx.CallAfter method. So you could post a
   message to the main GUI and have it do it's thing, then it could
   post a message back, so to speak. Hopefully Josiah or the pubsub
   creator can give both of us a clue.

Hi Mike,

I don't use pubsub myself so my solutions to questions here tend not to
include it either :slight_smile:

I don't know how to work with pubsub; I don't mean to flame against it
either. However, I think that messages sent with pubsub get processed on the
same thread as they are sent. I believe that the receivers of messages, in
pubsub framework, don't have limitations on the use of GUI. That would mean
you can not send a message to another thread, unless this is an option
somewhere. The Worker thread can send a message to a topic, and the
subscriber to the topic will pick it up, but processing will then happen all
in the same thread.

If the use of multiple threads for pubsub is an option which can be
activated somewhere, then there's still the problem that the Worker thread
needs to wait for the GUI thread to give it back an answer, and however you
arrange communication between Worker and GUI thread (wx.CallAfter,
messaging, pubsub), this is a problem which at the fundamental level is
solved by things like the Python threading.Event object, semaphores, locks,
and such.
One can build synchronous request-reply messaging models on top of that,
and perhaps one could even build that on top of pubsub, but my understanding
is that pubsub is not designed for such request-reply type of communication.
There is 1 publisher and 0-many subscribers. So if the Worker thread would
enter a wait-state, waiting for pubsub to give it a message on the
designated return-topic, it has no guarantee that there's a subscriber to
catch it's message, or that there are perhaps multiple subscribers who each
try to respond.
Sure, you can always give those guarantees in your code and the
threading.Event has the same problem: I'm trying to point out where the
conceptual mismatch is.

Hey, I hope that I haven't gone too far overboard on the theory, and that
I'm not misjudging pubsub too much! I don't mean to flame, I don't mean this
as a diatribe - sometimes I sound that way without meaning to.

I see that pubsub is good for many things and that I could myself use it
in many situations where I currently don't (binding with events instead),
but I don't think that the use of pubsub is applicable here in the use-case
where a background Worker Thread needs to make a request to the GUI Thread,
and also needs to wait for an answer.

   Mike

Regards,

--Tim :slight_smile:

Tim,

Don't worry about me. I like pubsub, but don't usually make Python scripts
that are complex enough to warrant its inclusion. The same is true of
threads. I use them from time to time, but not enough to be very familiar
with them. Threads are something I'd really like to learn better though. I
did a quick Google search and found this recipe which sounds like it might
work for this use-case:

http://code.activestate.com/recipes/491281/

It claims that it's "especially useful for non-blocking UI techniques and
for load distribution on jerky resources"

I'll let you be the judge of that.

Mike

_______________________________________________
wxpython-users mailing list
wxpython-users@lists.wxwidgets.org
http://lists.wxwidgets.org/mailman/listinfo/wxpython-users

CallQueue would work, but it's just another implementation of the
worker thread pattern.

As stated previously, pubsub doesn't do anything special, so...

What I would do, because I'm generally pretty lazy, is something like
the following...

SENTINEL = object

The above should be...

SENTINEL = object()

···

On Tue, Aug 19, 2008 at 11:47 AM, Josiah Carlson <josiah.carlson@gmail.com> wrote:

def get_password():
   x = [None]
   def get_password(window, message, destination, caption="Enter
Password", style=wx.OK|wx.CANCEL|wx.CENTRE):
       y = wx.PasswordEntryDialog(window, message, caption, style=style)
       if y.ShowModal() == wx.ID_OK:
           destination[0] = y.GetValue()
       else:
           destination[0] = SENTINEL
       y.Destroy()
   wx.CallAfter(get_password, ROOTWINDOW, "some message", x)

   while x[0] is None:
       time.sleep(.1)
   return x[0]

- Josiah

On Tue, Aug 19, 2008 at 11:32 AM, Mike Driscoll <mike@pythonlibrary.org> wrote:

Tim van der Leeuw wrote:

On Tue, Aug 19, 2008 at 7:00 PM, Mike Driscoll <mike@pythonlibrary.org >>> <mailto:mike@pythonlibrary.org>> wrote:

   Tim van der Leeuw wrote:

       On Tue, Aug 19, 2008 at 4:44 PM, Mike Driscoll >>> <mike@pythonlibrary.org <mailto:mike@pythonlibrary.org> >>> <mailto:mike@pythonlibrary.org >>> <mailto:mike@pythonlibrary.org>>> wrote:

          Steven Watanabe wrote:

              We've got multiple threads in our application, the gui
       thread
              and worker threads. A worker thread wants to display a
       modal
              dialog. I've read on this list that you can't call a wx gui
              function in a non-gui thread. But is it safe to create a wx
              MessageDialog in a worker thread, pass it to the gui thread
              and let the gui thread call ShowModal(), using a Python
              semaphore to block the worker thread until the result is
              available?

              If it isn't, is there a recommended way to accomplish this?

              Thanks. -Steven.

          I would just pass a message to the gui-thread that you want
       it to
          show a dialog using wx.CallAfter (which is thread-safe) and
       pubsub
          (which isn't).

       Well, but then how to get an answer back from the GUI thread,
       back to the Worker thread? That's what I solved, for my
       program, using the Event() object and setting extra properties
       on that Event object.

       The Worker Thread waits until the GUI thread calls
       event.set(), and then reads out the results from the Event object.

       Regards,

       --Tim

   This was more of a shot in the dark than anything. However, since
   pubsub isn't technically just for wx, you should be able to set up
   a receiver in any of your threads and just publish to them,
   probably using the wx.CallAfter method. So you could post a
   message to the main GUI and have it do it's thing, then it could
   post a message back, so to speak. Hopefully Josiah or the pubsub
   creator can give both of us a clue.

Hi Mike,

I don't use pubsub myself so my solutions to questions here tend not to
include it either :slight_smile:

I don't know how to work with pubsub; I don't mean to flame against it
either. However, I think that messages sent with pubsub get processed on the
same thread as they are sent. I believe that the receivers of messages, in
pubsub framework, don't have limitations on the use of GUI. That would mean
you can not send a message to another thread, unless this is an option
somewhere. The Worker thread can send a message to a topic, and the
subscriber to the topic will pick it up, but processing will then happen all
in the same thread.

If the use of multiple threads for pubsub is an option which can be
activated somewhere, then there's still the problem that the Worker thread
needs to wait for the GUI thread to give it back an answer, and however you
arrange communication between Worker and GUI thread (wx.CallAfter,
messaging, pubsub), this is a problem which at the fundamental level is
solved by things like the Python threading.Event object, semaphores, locks,
and such.
One can build synchronous request-reply messaging models on top of that,
and perhaps one could even build that on top of pubsub, but my understanding
is that pubsub is not designed for such request-reply type of communication.
There is 1 publisher and 0-many subscribers. So if the Worker thread would
enter a wait-state, waiting for pubsub to give it a message on the
designated return-topic, it has no guarantee that there's a subscriber to
catch it's message, or that there are perhaps multiple subscribers who each
try to respond.
Sure, you can always give those guarantees in your code and the
threading.Event has the same problem: I'm trying to point out where the
conceptual mismatch is.

Hey, I hope that I haven't gone too far overboard on the theory, and that
I'm not misjudging pubsub too much! I don't mean to flame, I don't mean this
as a diatribe - sometimes I sound that way without meaning to.

I see that pubsub is good for many things and that I could myself use it
in many situations where I currently don't (binding with events instead),
but I don't think that the use of pubsub is applicable here in the use-case
where a background Worker Thread needs to make a request to the GUI Thread,
and also needs to wait for an answer.

   Mike

Regards,

--Tim :slight_smile:

Tim,

Don't worry about me. I like pubsub, but don't usually make Python scripts
that are complex enough to warrant its inclusion. The same is true of
threads. I use them from time to time, but not enough to be very familiar
with them. Threads are something I'd really like to learn better though. I
did a quick Google search and found this recipe which sounds like it might
work for this use-case:

http://code.activestate.com/recipes/491281/

It claims that it's "especially useful for non-blocking UI techniques and
for load distribution on jerky resources"

I'll let you be the judge of that.

Mike

_______________________________________________
wxpython-users mailing list
wxpython-users@lists.wxwidgets.org
http://lists.wxwidgets.org/mailman/listinfo/wxpython-users

Tim van der Leeuw wrote:

    Steven Watanabe wrote:

        We've got multiple threads in our application, the gui thread
        and worker threads. A worker thread wants to display a modal
        dialog. I've read on this list that you can't call a wx gui
        function in a non-gui thread. But is it safe to create a wx
        MessageDialog in a worker thread, pass it to the gui thread and
        let the gui thread call ShowModal(), using a Python semaphore to
        block the worker thread until the result is available?

        If it isn't, is there a recommended way to accomplish this?

        Thanks. -Steven.

    I would just pass a message to the gui-thread that you want it to
    show a dialog using wx.CallAfter (which is thread-safe) and pubsub
    (which isn't).

Well, but then how to get an answer back from the GUI thread, back to
the Worker thread? That's what I solved, for my program, using the
Event() object and setting extra properties on that Event object.

The Worker Thread waits until the GUI thread calls event.set(), and then
reads out the results from the Event object.

Regards,

--Tim

Other possibilities:

- If a sender in a thread wants *one* result from a listener in main
thread, the simplest is to use wxCallAfter twice, and not use pubsub at
all: wxCallAfter used once to send the query to listener, and listener
calls wxCallAfter when result available. The disadvantage of this is
sender must know about listener, AND listener must know about sender.
The latter coupling is easy to break: sender, when doing the wxCallAfter
function call, also passes a reference to itself (or to a method of
itself where result should go). Pseudo-ishly:

  # main thread:
  def guiListener(arg1, resultCB):
    show modal dialog box, get result
    resultCB(result)

  # worker thread: ask for result, wait until we get it
  self.haveResult = False
  wxCallAfter(guiListener, arg1, self.storeResult) # ***
  while not self.haveResult: sleep(1)
  use result

  # worker method; will be called by guiListener from main thread:
  def storeResult(self, result):
    self.result = result
    self.haveResult = True

- If you also want sender to not know who to ask for a result, you could
use pubsub.sendMesage instead of guiListener in line ***:

  wxCallAfter(pubsub.sendMessage, "newDataAvailable",
              arg1=arg1, resultCB=self)

which will call pubsub.sendMessage from main thread, for topic
"newDataAvailable" and given topic message arguments. There could be
more than one listener that will get that message, doesn't matter; but
if more than one listener calls the result callback, the sender must be
able to handle multiple results (or have it just use the latest etc).

I don't see much point in publishing the dialog result from main thread
unless there are several parts of your code that would be interested in
the result. In this case guiListener can use pubsub.sendMessage, which
would call storeResult in main thread, just like the first method does.
It may be necessary to mutex the read/write of self.haveResult (nothing
specific to pubsub) but in a lot of cases you won't even need that.

Note that a more pubsub-ish design of the worker thread would be "a
worker thread wants to know something from user"; it shouldn't care
whether it's via a dialog box or console shell window or from a cached
answer in a file etc. It just wants an answer!

Oliver

···

On Tue, Aug 19, 2008 at 4:44 PM, Mike Driscoll <mike@pythonlibrary.org > <mailto:mike@pythonlibrary.org>> wrote:

Tim van der Leeuw wrote:

    Tim van der Leeuw wrote:

           Steven Watanabe wrote:

               We've got multiple threads in our application, the gui thread
               and worker threads. A worker thread wants to display a modal
               dialog. I've read on this list that you can't call a wx gui
               function in a non-gui thread. But is it safe to create a wx
               MessageDialog in a worker thread, pass it to the gui thread
               and let the gui thread call ShowModal(), using a Python
               semaphore to block the worker thread until the result is
               available?

               If it isn't, is there a recommended way to accomplish this?

               Thanks. -Steven.

           I would just pass a message to the gui-thread that you want it to
           show a dialog using wx.CallAfter (which is thread-safe) and
        pubsub
           (which isn't).

        Well, but then how to get an answer back from the GUI thread,
        back to the Worker thread? That's what I solved, for my program,
        using the Event() object and setting extra properties on that
        Event object.

        The Worker Thread waits until the GUI thread calls event.set(),
        and then reads out the results from the Event object.

        Regards,

        --Tim
         
    This was more of a shot in the dark than anything. However, since
    pubsub isn't technically just for wx, you should be able to set up a
    receiver in any of your threads and just publish to them, probably
    using the wx.CallAfter method. So you could post a message to the
    main GUI and have it do it's thing, then it could post a message
    back, so to speak. Hopefully Josiah or the pubsub creator can give
    both of us a clue.

[...]
but I don't think that the use of pubsub is applicable here in
the use-case where a background Worker Thread needs to make a request to
the GUI Thread, and also needs to wait for an answer.

I agree (even as the current developer of pubsub :} )
Oliver

···

On Tue, Aug 19, 2008 at 7:00 PM, Mike Driscoll <mike@pythonlibrary.org > <mailto:mike@pythonlibrary.org>> wrote:
        On Tue, Aug 19, 2008 at 4:44 PM, Mike Driscoll > <mike@pythonlibrary.org <mailto:mike@pythonlibrary.org> > <mailto:mike@pythonlibrary.org>> > wrote:

Oliver Schoenborn wrote:

Other possibilities:

- If a sender in a thread wants *one* result from a listener in main
thread, the simplest is to use wxCallAfter twice, and not use pubsub at
all: wxCallAfter used once to send the query to listener, and listener
calls wxCallAfter when result available. The disadvantage of this is
sender must know about listener, AND listener must know about sender.
The latter coupling is easy to break: sender, when doing the wxCallAfter
function call, also passes a reference to itself (or to a method of
itself where result should go). Pseudo-ishly:

  # main thread:
  def guiListener(arg1, resultCB):
    show modal dialog box, get result
    resultCB(result)
  

If I understand you well, the line above should be done through wx.CallAfter ?
Or where else is the second wx.CallAfter ?

thanks,
Stef Mientki

···

  # worker thread: ask for result, wait until we get it
  self.haveResult = False
  wxCallAfter(guiListener, arg1, self.storeResult) # ***
  while not self.haveResult: sleep(1)
  use result

  # worker method; will be called by guiListener from main thread:
  def storeResult(self, result):
    self.result = result
    self.haveResult = True

- If you also want sender to not know who to ask for a result, you could
use pubsub.sendMesage instead of guiListener in line ***:

  wxCallAfter(pubsub.sendMessage, "newDataAvailable",
              arg1=arg1, resultCB=self)

which will call pubsub.sendMessage from main thread, for topic
"newDataAvailable" and given topic message arguments. There could be
more than one listener that will get that message, doesn't matter; but
if more than one listener calls the result callback, the sender must be
able to handle multiple results (or have it just use the latest etc).

I don't see much point in publishing the dialog result from main thread
unless there are several parts of your code that would be interested in
the result. In this case guiListener can use pubsub.sendMessage, which
would call storeResult in main thread, just like the first method does.
It may be necessary to mutex the read/write of self.haveResult (nothing
specific to pubsub) but in a lot of cases you won't even need that.

Note that a more pubsub-ish design of the worker thread would be "a
worker thread wants to know something from user"; it shouldn't care
whether it's via a dialog box or console shell window or from a cached
answer in a file etc. It just wants an answer!

Oliver
_______________________________________________
wxpython-users mailing list
wxpython-users@lists.wxwidgets.org
http://lists.wxwidgets.org/mailman/listinfo/wxpython-users

Stef Mientki wrote:

Oliver Schoenborn wrote:

Other possibilities:

- If a sender in a thread wants *one* result from a listener in main
thread, the simplest is to use wxCallAfter twice, and not use pubsub at
all: wxCallAfter used once to send the query to listener, and listener
calls wxCallAfter when result available. The disadvantage of this is
sender must know about listener, AND listener must know about sender.
The latter coupling is easy to break: sender, when doing the wxCallAfter
function call, also passes a reference to itself (or to a method of
itself where result should go). Pseudo-ishly:

  # main thread:
  def guiListener(arg1, resultCB):
    show modal dialog box, get result
    resultCB(result)
  

If I understand you well, the line above should be done through
wx.CallAfter ?
Or where else is the second wx.CallAfter ?

thanks,
Stef Mientki

Sorry, I forgot to fix that in my email: the second wxCallAfter is not
required, but could be useful in some cases (e.g. to allow the GUI to
process pending events -- perhaps other threads should get a chance to
get their dialogs shown before the results are sent). The second
wxCallAfter would, as you say, wrap the resultCB(result) line.
Oliver

Tim van der Leeuw wrote:

I see that pubsub is good for many things and that I could myself use it in many situations where I currently don't (binding with events instead), but I don't think that the use of pubsub is applicable here in the use-case where a background Worker Thread needs to make a request to the GUI Thread, and also needs to wait for an answer.

Take a look at wx.lib.delayedresult, I think it was intended for situations like this.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!