Multithreaded COM server problem...

John Lull jl at windsmith.net
Fri Jan 16 14:50:08 CET 2004


Mark Hammond <mhammond at skippinet.com.au> wrote (with possible
deletions):

> John Lull wrote:
> > Mark Hammond <mhammond at skippinet.com.au> wrote (with possible
> > deletions):
> > 
> > 
> >>John Lull wrote:
> > 
> > ...
> > 
> >>>Unfortunately, this one has to be a local server since it's providing shared
> >>>access to a pool of hardware devices from multiple distributed clients. I've
> >>>carefully reviewed chapters 5 & 12, and appendix D, and wasn't able to find
> >>>anything addressing threading models in the local server in detail. If I've
> >>>missed something, I'd be grateful for any additional hints. 
> >>
> >>The problem is that your client code is not running a message loop.  If 
> >>you change the loop of your client test code to something like:
> >>
> >>for i in range(delay)*10:
> >>     time.sleep(0.1)
> >>     pythoncom.PumpWaitingMessages()
> >>
> >>It works as you expect.  A better choice would probably be 
> >>win32event.MsgWaitForMultipleObjects, but that depends on what your app 
> >>really does.
> >>
> >>Mark.
> > 
> > 
> > I presume you meant my server code. 
> 
> Nope - I meant the client.  The server is already running such a loop 
> thank to localserver.py, which is hosting the object.
> 
> The client code's main (and only) thread is blocked in a system call, 
> but it appears COM wants it to pump messages so the marshalling magic 
> happens.  I can only speculate why COM needs this to happen in this 
> trivial case, but COM's rules do state this requirement.

Now I'm *really* confused.

Perhaps I need to clarify a bit. The sleep() method in my sample
server is a perhaps-too-simplified substitute for what the real server
is doing. It provides a variety of high-level operations on a piece of
hardware. Some of the operations take as long as several dozen
seconds, others take a millisecond or so. I need the client to block
waiting for completion of each operation, regardless of how long the
operation takes. I cannot break one of the long operations up into a
series of calls from the client -- it must be implemented as a single
call. My example would, perhaps, have been clearer if I'd named the
method someLongRunningMethod() instead of sleep().

I've tried doing roughly what you suggested inside my test client,
calling PumpWaitingMessages() both before and after each COM
operation. That still leaves me with the same basic problem -- inside
the server, all of my COM objects are created on the server's main
thread, instead of on a separate thread for each client. That leaves
all COM operations serialized through that single thread. My test
client at the moment looks like this:

  import sys
  from pythoncom import PumpWaitingMessages
  from win32com.client import Dispatch

  PumpWaitingMessages()
  app=Dispatch('PyComThreads.Application')
  PumpWaitingMessages()
  app.someLongRunningMethod(20)
  PumpWaitingMessages()

If this is not essentially what you meant, could you please let me
know? The server is exactly like I had posted originally, except for
renaming its sleep() method to someLongRunningMethod().


> That sucks, and is almost certainly a thread-state error.

That was my thought.


Thanks.

Regards,
John



More information about the Python-list mailing list