jf...@ms4.hinet.net wrote: > Peter Otten at 2015/11/28 UTC+8 6:14:09PM wrote: >> No, the point of both recipes is that tkinter operations are only ever >> invoked from the main thread. The main thread has polling code that >> repeatedly looks if there are results from the helper thread. As far I >> understand the polling method has the structure >> >> f(): >> # did we get something back from the other thread? >> # a queue is used to avoid race conditions >> >> # if yes react. >> # var_status.set() goes here >> >> # reschedule f to run again in a few millisecs; >> # that's what after() does > > Have no idea how the main thread poll on all those events (or it use a > queue)? All I know now is that the main thread(mainloop()?) can be easily > blocked by event handlers if the handler didn't run as a separate thread. > >> > ..... >> > ..... >> > #do the rest >> > var_status.set('Download...') >> > _thread.start_new_thread(td_download, ()) #must use threading >> > >> > def td_download(): >> > result = mydll.SayHello() >> > if result: >> > var_status.set("Download Fail at %s" % hex(result)) >> > showerror('Romter', 'Download Fail') >> > else: >> > var_status.set('Download OK') >> > showinfo('Romter', 'Download OK') >> >> As td_download() runs in the other thread the var_status.set() methods >> are problematic. > > No idea what kind of problem it will encounter. Can you explain?
While the var_status.set() invoked from the second thread modifies some internal data the main thread could kick in and modify (parts of) that same data, thus bringing tkinter into an broken state. A simple example that demonstrates the problem: import random import threading import time account = 70 def withdraw(delay, amount): global account if account >= amount: print("withdrawing", amount) account -= amount else: print("failed to withdraw", amount) threads = [] for i in range(10): t = threading.Thread( target=withdraw, kwargs=dict(delay=.1, amount=random.randrange(1, 20))) threads.append(t) t.start() for t in threads: t.join() Before every withdrawal there seems to be a check that ensures that there is enough money left, but when you run the script a few times you will still sometimes end with a negative balance. That happens when thread A finds enough money, then execution switches to thread B which also finds enough money, then both threads perform a withdrawal -- oops there wasn't enough money for both. >> Another complication that inevitably comes with concurrency: what if the >> user triggers another download while one download is already running? If >> you don't keep track of all downloads the message will already switch to >> "Download OK" while one download is still running. > > Hummm...this thought never comes to my mind. After take a quick test I > found, you are right, a second "download" was triggered immediately. > That's a shock to me. I suppose the same event shouldn't be triggered > again, or at least not triggered immediately, before its previous handler > was completed. ...I will take a check later on Borland C++ builder to see > how it reacts! > > Anyway to prevent this happens? if Python didn't take care it for us. A simple measure would be to disable the button until the download has ended. -- https://mail.python.org/mailman/listinfo/python-list