473,785 Members | 2,736 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Multithreaded COM server problem...

I'm writing a multithreaded COM server to manage a pool of hardware resources.
All objects are designed to be thread-safe, and I've set sys.coinit_flag s to
COINIT_MULTITHR EADED before importing pythoncom.

The problem is that all requests to the server seem to be serialized by COM. To
demonstrate the problem, I'm including a simple test server that exposes one
interface object, PyComThreads.Ap plication, with a single method sleep(delay).
I'm also including 2 test programs -- test20.py uses the server to delay 20
seconds, and test1.py delays only one second. The server prints status messages
to the trace collector debugging tool when creating the Application object, and
at the beginning and end of the specified delay.
When I run the 20-second test program, then a couple seconds later run the
1-second test program, I had expected to see something like this:

Object 8087872 in thread 8160416 created
Object 8087872 in thread 8160416 delays 20 seconds
Object 8086008 in thread 8156272 created
Object 8086008 in thread 8156272 delays 1 seconds
Object 8086008 delay ends
Object 8087872 delay ends
Instead, I see:

Object 8087872 in thread 8160416 created
Object 8087872 in thread 8160416 delays 20 seconds
Object 8087872 delay ends
Object 8086008 in thread 8160416 created
Object 8086008 in thread 8160416 delays 1 seconds
Object 8086008 delay ends
Apparently the requests from both client applications are being serialized by
the COM interface.

I need each request (or at least each interface object) to run in its own
thread, or in a pool of threads, and haven't been able to figure out how to
accomplish this. Any suggestions would be appreciated.
Regards,
John

----------
PyComThreads.py :

import sys
import threading
from time import sleep
import win32traceutil

sys.coinit_flag s = 0 # 0 == pythoncom.COINI T_MULTITHREADED # !!!!!
import pythoncom

class Application:
""" Test version of a Multi-threaded local server """

_reg_progid_ = 'PyComThreads.A pplication'
_reg_verprogid_ = 'PyComThreads.A pplication.100'
_reg_clsctx_ = pythoncom.CLSCT X_LOCAL_SERVER
_reg_clsid_ = '{56BEC27D-EDC4-43A0-AEB7-77E4A1381C0F}'

_public_methods _ = ['sleep']
_public_attrs_ = []
_readonly_attrs _ = []

def __init__(self):
print 'Object %s in thread %s created' % \
(id(self), id(threading.cu rrentThread()))

def sleep(self, delay):
print 'Object %s in thread %s delays %s seconds' % \
(id(self), id(threading.cu rrentThread()), delay)
sleep(delay)
print 'Object %s delay ends' % id(self)

# COM server registration, etc.
if __name__ == '__main__':
if hasattr(sys, 'argv'):
# If *no* command-line arguments, we were not invoked as a server.
# Assume the user wants us to self-register.
if len(sys.argv) == 1:
sys.argv.append ('--register')

import win32com.server .register
win32com.server .register.UseCo mmandLine(Appli cation, debug=0)

----------
test20.py:

from win32com.client import Dispatch
app=Dispatch('P yComThreads.App lication')
app.sleep(20)

----------
test1.py:

from win32com.client import Dispatch
app=Dispatch('P yComThreads.App lication')
app.sleep(1)

Jul 18 '05 #1
9 16277
Hi !
* Sorry for my bad english : french is very more easy, and nice ;-) *

I have try another way. I use a procedure for manage thread :

GlobalTacheID=[None]*16

def tache(ordre, numtache=1, nomtache=None, fonction=None):
global GlobalTacheID
import threading
if ordre=="Lance":
GlobalTacheID[numtache] =
threading.Threa d(target=foncti on,name=nomtach e)
GlobalTacheID[numtache].start()
print(nomtache+ ' num.'+str(numta che))
elif ordre=="Liste":
return(string.j oin(threading.e numerate(),'\n' ))
elif ordre=="Etat":
return(str(Glob alTacheID[numtache].isAlive()))

And, in my public_method, i call this procedure, with the parameters
"ordre=Lanc e" for run a thread, "ordre=Etat " for see his state (fonction=
the name of the method 'threaded').

And it's OK. I can run a thread from an Excel-COM-client. I can also run an
thread on a method caontained in a string gived by Excel.

Python is very smart-dynamic-agile language.

Bonne soirée
--
Michel Claveau
mél : http://cerbermail.com/?6J1TthIa8B
site : http://mclaveau.com
Jul 18 '05 #2
John Lull wrote:
I'm writing a multithreaded COM server to manage a pool of hardware resources.
All objects are designed to be thread-safe, and I've set sys.coinit_flag s to
COINIT_MULTITHR EADED before importing pythoncom.


Note that this flag is effeectively ignored for the server. Objects are
created in the same "apartment" as their creator. This, the code
implementing your object need not specify this, but the code *creating*
the object must. This is what determines the appartment.

COM threading rules are complex, but "Python Programming on Win32" (1/2
by me :) covers these rules in words I would have trouble finding again :)

Mark.

Jul 18 '05 #3
Mark Hammond <mh******@skipp inet.com.au> wrote (with possible deletions):
John Lull wrote:
I'm writing a multithreaded COM server to manage a pool of hardware resources.
All objects are designed to be thread-safe, and I've set sys.coinit_flag s to
COINIT_MULTITHR EADED before importing pythoncom.


Note that this flag is effeectively ignored for the server. Objects are
created in the same "apartment" as their creator. This, the code
implementing your object need not specify this, but the code *creating*
the object must. This is what determines the appartment.

COM threading rules are complex, but "Python Programming on Win32" (1/2
by me :) covers these rules in words I would have trouble finding again :)


It covers threading rules for in-process servers pretty thoroughly.

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.

Thanks.
Regards,
John

Jul 18 '05 #4
John Lull wrote:
Mark Hammond <mh******@skipp inet.com.au> wrote (with possible deletions):

John Lull wrote:

I'm writing a multithreaded COM server to manage a pool of hardware resources.
All objects are designed to be thread-safe, and I've set sys.coinit_flag s to
COINIT_MULTI THREADED before importing pythoncom.


Note that this flag is effeectively ignored for the server. Objects are
created in the same "apartment" as their creator. This, the code
implementin g your object need not specify this, but the code *creating*
the object must. This is what determines the appartment.

COM threading rules are complex, but "Python Programming on Win32" (1/2
by me :) covers these rules in words I would have trouble finding again :)

It covers threading rules for in-process servers pretty thoroughly.

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.PumpW aitingMessages( )

It works as you expect. A better choice would probably be
win32event.MsgW aitForMultipleO bjects, but that depends on what your app
really does.

Mark.

Jul 18 '05 #5
John Lull wrote:
Mark Hammond <mh******@skipp inet.com.au> wrote (with possible
deletions):

John Lull wrote:
...
Unfortunatel y, 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.PumpW aitingMessages( )

It works as you expect. A better choice would probably be
win32event.Ms gWaitForMultipl eObjects, 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.
This still leaves all calls to the
server running in a single thread, however. If I insert a call to
PumpWaitingMess ages() in a short operation, and it happens to start a
long operation, the result of that short operation will be delayed
until the long operation completes. This will make my server unusable.
Make the change I suggested, and it works as you hope.
At first glance this seems to do what I want -- requests to the server
seem to run from a thread pool. However, I also get intermittent (but
frequest) startup errors, with a Microsoft Visual C++ Runtime Library
error dialog (during pythoncom.PumpM essages but before my server
module gets imported) reporting:
Runtime Error!
Program: c:\Apps\Python2 .2\pythonw.exe
abnormal program termination


That sucks, and is almost certainly a thread-state error. If you have a
debug build of Python, it will offer to break into the debugger at this
point.

Mark.

Jul 18 '05 #6
Mark Hammond <mh******@skipp inet.com.au> wrote (with possible
deletions):
John Lull wrote:
Mark Hammond <mh******@skipp inet.com.au> wrote (with possible
deletions):

John Lull wrote:
...
Unfortunatel y, 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.PumpW aitingMessages( )

It works as you expect. A better choice would probably be
win32event.Ms gWaitForMultipl eObjects, 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 someLongRunning Method() instead of sleep().

I've tried doing roughly what you suggested inside my test client,
calling PumpWaitingMess ages() 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 PumpWaitingMess ages
from win32com.client import Dispatch

PumpWaitingMess ages()
app=Dispatch('P yComThreads.App lication')
PumpWaitingMess ages()
app.someLongRun ningMethod(20)
PumpWaitingMess ages()

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 someLongRunning Method().

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


That was my thought.
Thanks.

Regards,
John
Jul 18 '05 #7
John Lull wrote:
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 someLongRunning Method() instead of sleep().


Is there any way you can do it asynchronously? The main thread spawns a
second thread to do the work. The main thread then spins around a
MsgWaitForMulti pleObjects, with an object set by the second thread. The
main thread will then be able to run a message pump, but also detect
when the second thread is done.

Apart from that, I am afraid I am out of ideas. I believe however that
you are hitting pure COM issues, and nothing related to Python. Looking
for the answer beyond the Python world may be fruitful.

Mark.

Jul 18 '05 #8
Mark Hammond <mh******@skipp inet.com.au> wrote (with possible
deletions):
Is there any way you can do it asynchronously? The main thread spawns a
second thread to do the work. The main thread then spins around a
MsgWaitForMulti pleObjects, with an object set by the second thread. The
main thread will then be able to run a message pump, but also detect
when the second thread is done.
Yes, except there doesn't seem to be any way to return a value from
the first call until after the second call completes.
Apart from that, I am afraid I am out of ideas. I believe however that
you are hitting pure COM issues, and nothing related to Python. Looking
for the answer beyond the Python world may be fruitful.


The three reasonable possibilities I see at the moment are:

1. Dig into exactly how apartment-threaded servers are supposed to be
written in C or C++ & see how much of that is transferrable to Python.
I'm not confident this would give me a solution, though.

2. Activate the server in 2 steps -- have the main thread create (on
client request) "interlock" object that, when created, fires up a new
thread for the client who created it. The new thread then calls
factory.Registe rClassFactories () for the real worker object, then
starts a message pump. The client then requests COM to create the
worker object. The worker object creation method then calls
factory.RevokeC lassFactories() to revoke that thread's registration.
The interlock and worker classes have to coordinate so that only one
worker thread is registered as class factory at any time, and only one
client is able to create the worker object at any time. The main
thread also has to register as class factory only for the interlock
object, not for the worker object. This requires changes to one py2exe
module and to all applications that use my server, and will complicate
shutdown, since I have to shut down the new thread only when all
object's it's pumping messages for are gone. There's also the
substantial possibility that the same bug I ran into when setting
sys.coinit_flag s=0 in localserver.py will rear its head here.

3. Dig into why setting sys.coinit_flag s=0 in localserver.py doesn't
work. This is probably the right thing to do, both because I know it
will yield a solution, and because it would solve the same issue for
anyone else with similar needs. Unfortunately it means I have to dig
into Python threading internals, pythoncom internals, and the whole
COM mechanism rather more heavily than I'd hoped to.
Regards,
John

Jul 18 '05 #9
John Lull wrote:
1. Dig into exactly how apartment-threaded servers are supposed to be
written in C or C++ & see how much of that is transferrable to Python.
I'm not confident this would give me a solution, though. .... 3. Dig into why setting sys.coinit_flag s=0 in localserver.py doesn't
work. This is probably the right thing to do, both because I know it
will yield a solution, and because it would solve the same issue for
anyone else with similar needs. Unfortunately it means I have to dig
into Python threading internals, pythoncom internals, and the whole
COM mechanism rather more heavily than I'd hoped to.


I think these are pretty-much the same option. The win32com extensions
make no attempt to insulate you from these threading issues - it will
blindly do what you ask. In that regard, Python already acts very much
like a C/C++ application - under the covers, we have a C++ pointer to a
COM object, and when Python code tries to make a call, from whatever
thread, we just make the call. The same thing is true in reverse - we
hand out a C++ pointer, and when an incoming call is made on that, we
blindly call Python on that thread.

The Python GIL is in the picture, but I see no evidence it has any
bearing in this case. Certainly, in the simple example we started with,
no threads were blocked waiting for this lock.

Re sys.soinit_flag s - I am fairly confident that this will cause
CoInitEx to be called with the specified flag as pythoncom is imported.
However, note that any exceptions raised by this function are masked
when called implicitly during that import. Try explicitly calling
pythoncom.CoIni tializeEx(0) near the top of localserver.py - any
exceptions you see would also have happened for the implicit call made
at import time.

I'd welcome any evidence that a C++ app would behave differently, and am
keen to help you resolve (or at least explain) this for everyone's
future benefit.

Mark.

Jul 18 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
2983
by: Elbert Lev | last post by:
I started with Python two weeks ago and already saved some time and efforts while writing 2 programs: 1. database extraction and backup tool, which runs once a month and creates a snapshot of important data, compresses and saves it. 2. pop3 "watchdog", which reads e-mail from a pop3 mailbox and in the case there is no mail sends e-mail messages to technicians. (the presence of e-mail in the mailbox tells that the system I'm monitoring...
2
6642
by: pradyumna | last post by:
In Project settins - C/C++ - Code Generation, what is the difference between the option "Multithreaded" and "Multithreaded DLL". I understand that on selecting multithreaded option, single and multithreaded applications can both use that dll, but what about multithreaded DLL option. Thanks
6
2788
by: Dan Kelley | last post by:
We have a multithreaded app that responds to events, and writes these events to a text file. This text file is used by an external system for further processing. We want to be able to write multiple entries to the file, and then rename it and copy it to a new location when the file reaches a certian size, or a certain time span elapses (which ever comes first). I have created a static/shared timer member variable in class that writes...
1
2344
by: daniel.bron | last post by:
I'm maintaining a C++ application written by a developer who has now left. The app is a multithreaded client/server app for financial data. My compiler is MS visual C++ 6.0. I'm a C++ neophyte. I took some C (not C++) courses in college, this is the only production C++ code I've worked with. I'm trying to add some logging, and having problems. My logging scheme is to have a global ofstream, which I initialize in a
7
5324
by: Sidd | last post by:
Hi, I tried finding and example of multithreaded client-serve program in python. Can any one please tell me how to write a multithreaded client-server programn in python such that 1.It can handle multiple connections 2.It uses actual threads and not select() or some other function
7
2274
by: Pavils Jurjans | last post by:
Hello, I wanted to get some light in the subject. As I develop ASP.NET applications, it's necessary to understand how exactly the server- communication happens. It seems like initially application is "sleeping", and it is not loaded in the memory. Then, after very first request to the app, it is compiled (aspx files), loaded into memory, and executed. Then, a separate thread is issued to serve my page request, and it takes care for me...
2
1684
by: Alan Kemp | last post by:
Hi, I have a problem that is half python, half design. I have a multithreaded network server working, each client request spawns a new thread which deals with that client for as long as it is connected (think ftp style rather than http style connections here). Each thread gets passed a reference to the main server to access things like the list of connected clients, global data, etc. Now I want to add a database to store usernames...
3
2644
by: akmkat | last post by:
Hi all, I am in a great problem. I am trying to implement a multithreaded server using java, first look at the code... /*------- Main Server (server.java)--------------*/ import java.io.* ; import java.net.* ; public class server {
4
3694
by: cj | last post by:
I have a multithreaded transaction processing app that now needs to write to a sql db. I assume I will have to make the connection in the main program and then each thread/transaction would create it's own command and execute it? Is this correct?
0
9643
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9480
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10319
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9947
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
7496
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6737
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5511
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
3645
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2877
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.