Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
296 views
in Technique[技术] by (71.8m points)

multithreading - Python thread: The application called an interface that was marshalled for a different thread

The following code works without errors:

 self.sim.create_pnl_results(gui_values, dfs)

This code gives me an error:

thread = Thread(target=self.sim.create_pnl_results, args=(gui_values, dfs))
thread.start()

in _ApplyTypes_ self._oleobj_.InvokeTypes(dispid, 0, wFlags, retType, argTypes, *args),
com_error: (-2147417842, 'The application called an interface that was marshalled for a different thread.', None, None)

It seems that the application calls a com object somewhere further down the line and because I would like to put a gui (QT) on top I need to make it a separate thread. How can I avoid the above error message? I have read that it is connected to a windows problem. Any suggestions how to resolve it in python would be appreciated. I have no control on the com objects that are called from the application and I don't see why it would make a difference if I call them from the main thread of a new thread.

additional information about how the com object is called:

def process_ts(*args):
    ts_id, i, dfn , ts_queue = args
    pythoncom.CoInitialize()
    ts = win32com.client.Dispatch(pythoncom.CoGetInterfaceAndReleaseStream(ts_id, pythoncom.IID_IDispatch))
    ts_queue.put( tuple([i , ACRF._com_to_ts(ts, i, dfn)]) )
    pythoncom.CoUninitialize ()
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Many (if not most) GUI applications run into problems if you try to update/redraw the UI from another thread. Just imagine what would happen if you had one thread trying to write "blue" 100x to a file, and another thread trying to write "red" 100x. You'll see something like:

redblueredblruede...

(granted with Python you have the GIL so you might not get precisely that same effect, but using multiprocessing you could probably make it happen).

The exact same thing would happen to your graphical application if one thread is trying to turn a region blue, while the other is trying to turn it red. Because that's undesirable, there are guards put in place to stop it from happening by throwing exceptions like the one you encountered.

What you have happening here is something like this:

----(UI Thread)-,----------------->
                 
                  `---(new thread)-----(affect the UI)-X kaboom!

What you want to have happen is something like this:

----(UI Thread)-,--------------------------------------,---(affect the UI)-->
                                                     /
                  `---(new thread)-----(pass result)-`

The exact mechanics of it will change from framework to framework. In .NET you've got an if (thing.InvokeRequired){ thing.BeginInvoke(data); }

On Windows, COM objects are protected the same sort of way. If you create an COM object on a thread it doesn't like you trying to access it on a different thread. So if you're creating it on a different thread and you still need to interact with it you're going to have to communicate across your threads.

If your code isn't blocking, or it doesn't take very long to run (i.e. < 250ms) then running the calls on the main thread should be just fine. Typically UI frameworks allow you to register a callback to be executed after N amount of time, and then it will just be executed on the main thread whenever it can be.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...