I need to generate virtual events for a tkinter window running in a separate thread. Calling event_generate from non-gui thread is supposed to be safe and it works well, when tkinter runs in the main thread and events are generated in another thread.
For a certain reason I need that the statements generating the events run in main thread (more specifically, I want those statements to be in the toplevel of the module).
But, when I do root = Tk(); root.mainloop() in a new thread and root.event_generate("<<my-event>>") in the main thread, I get stack overflow. When I swap the threads (root = Tk(); root.mainloop() in the main thread and root.event_generate("<<my-event>>") in a new thread) then everything works again.
I have taken care that root is fully construted (and also idle), before I try generating the event.
Any ideas how to get this setup working?
(I'm using Python 3.2.3)
Found the answer myself: put only root.mainloop() in secondary thread, keep root = Tk() in main thread.
Related
Trying to create a event loop inside a thread, where the thread is initiated within the constructor of a class. I want to run multiple tasks within the event loop. However, having an issue whenever I try to run with the thread and get the error "NoneType object has no attribute create_task"
Is there something I am doing wrong in calling it.
import asyncio
import threading
Class Test():
def __init__(self):
self.loop = None
self.th = threading.Thread(target=self.create)
self.th.start()
def __del__(self):
self.loop.close()
def self.create(self):
self.loop = new_event_loop()
asyncio.set_event_loop(self.loop)
def fun(self):
task = self.loop.create_task(coroutine)
loop.run_until_complete(task)
def fun2(self):
task = self.loop.create_task(coroutine)
loop.run_until_complete(task)
t = Test()
t.fun()
t.fun2()
It is tricky to combine threading and asyncio, although it can be useful if done properly.
The code you gave has several syntax errors, so obviously it isn't the code you are actually running. Please, in the future, check your post carefully out of respect for the time of those who answer questions here. You'll get better and quicker answers if you spot these avoidable errors yourself.
The keyword "class" should not be capitalized.
The class definition does not need empty parenthesis.
The function definition for create should not have self. in front of it.
There is no variable named coroutine defined in the script.
The next problem is the launching of the secondary thread. The method threading.Thread.start() does not wait for the thread to actually start. The new thread is "pending" and will start sometime soon, but you don't have control over when that happens. So start() returns immediately; your __init__ method returns; and your call to t.fun() happens before the thread starts. At that point self.loop is in fact None, as the error message indicates.
An nice way to overcome this is with a threading.Barrier object, which can be used to insure that the thread has started before the __init__ method returns.
Your __del__ method is probably not necessary, and will normally only get executed during program shut down. If it runs under any other circumstances, you will get an error if you call loop.close on a loop that is still running. I think it's better to insure that the thread shuts down cleanly, so I've provided a Test.close method for that purpose.
Your functions fun and fun2 are written in a way that makes them not very useful. You start a task and then you immediately wait for it to finish. In that case, there's no good reason to use asyncio at all. The whole idea of asyncio is to run more than one task concurrently. Creating tasks one at a time and always waiting for each one to finish doesn't make a lot of sense.
Most asyncio functions are not threadsafe. You have to use the two important methods loop.call_soon_threadsafe and asyncio.run_coroutine_threadsafe if you want to run asyncio code across threads. The methods fun and fun2 execute in the main thread, so you should use run_coroutine_threadsafe to launch tasks in the secondary thread.
Finally, with such programs it's usually a good idea to provide a thread shutdown method. In the following listing, close obtains a list of all the running tasks, sends a cancel message to each, and then sends the stop command to the loop itself. Then it waits for the thread to really exit. The main thread will be blocked until the secondary thread is finished, so the program will shut down cleanly.
Here is a simple working program, with all the functionality that you seem to want:
import asyncio
import threading
async def coro(s):
print(s)
await asyncio.sleep(3.0)
class Test:
def __init__(self):
self.loop = None
self.barrier = threading.Barrier(2) # Added
self.th = threading.Thread(target=self.create)
self.th.start()
self.barrier.wait() # Blocks until the new thread is running
def create(self):
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.loop)
self.barrier.wait()
print("Thread started")
self.loop.run_forever()
print("Loop stopped")
self.loop.close() # Clean up loop resources
def close(self): # call this from main thread
self.loop.call_soon_threadsafe(self._close)
self.th.join() # Wait for the thread to exit (insures loop is closed)
def _close(self): # Executes in thread self.th
tasks = asyncio.all_tasks(self.loop)
for task in tasks:
task.cancel()
self.loop.call_soon(self.loop.stop)
def fun(self):
return asyncio.run_coroutine_threadsafe(coro("Hello 1"), self.loop)
def fun2(self):
return asyncio.run_coroutine_threadsafe(coro("Hello 2"), self.loop)
t = Test()
print("Test constructor complete")
t.fun()
fut = t.fun2()
# Comment out the next line if you don't want to wait here
# fut.result() # Wait for fun2 to finish
print("Closing")
t.close()
print("Finished")
I'm playing a bit with event machine, and got some code that run on another thread, I want his callback to get synced back to the main thread, so I'd like to do something like this:
thread.post { fiber.resume(result) }
The fiber parent is thread but context of execution is on another thread.
thanks,
Found it
EventMachine.schedule
does the trick
I have a simple code that does this:
private List<DicomImage> img = new List<DicomImage>();
Parallel.ForEach(ofdmulti.FileNames, filename =>
{
img.Add(new DicomImage(filename));
Progress_Bar_Loading_Images.PerformStep();
}
);
When I execute it, I get an error:
"Cross-thread operation not valid: Control 'Progress_Bar_Loading_Images' accessed from a
thread other than the thread it was created on."
How can I solve that without removing the progress bar? I really need it to show the progress
When you use Parallel.Foreach, each iteration (or a group of it) is perfomed on another thread (luckly on a different processor) concurrently. However, progressbar is working on main thread (or GUI thread) so you need to synchronize your threads after each call to progress bar.
An important thing to mention in here is synchronizing for each step is slow and pointless.So I suggest you to put a condition dependent on the modulus of an index to say "synchronize for each 10 steps".
I need to trasmit with a (Boost) tcp server information collected in real time by the ARToolKit video tracking library.
Which is the right way of doing it?
I'm actually doing it with Boost threads and asio, but I think that what I do is done in a bad way (even if it works)
Here is what I do to run the server (the source of the Server class is from Boost tutorial):
boost::asio::io_service io_service;
Server s(io_service, 2345);
boost::thread bt(boost::bind(&boost::asio::io_service::run, &io_service)); //server in background in a second thread
Then I start the video tracking
startTracking(); //blocking call in the main thread
defined in this way
void startTracking(){
glutInit(&argc, argv); //global and reachable
if ((gArglSettings = arglSetupForCurrentContext()) == NULL) {
fprintf(stderr, "main(): arglSetupForCurrentContext() returned error.\n");
exit(-1);}
... //init a lot of artoolkit parameters
arVideoCapStart();
argMainLoop( NULL, keyEvent, mainLoop );
}
In this (horrible) way everything works. But I would like to avoid spawning a second thread for the asio server (it is not supposed to be thrown there, as I read from the Boost doc).
Otherwise trying to put the video traking out of the main thread crashes the ARToolKit library ie:
boost::thread workerThread(startTracking);
workerThread.join();
When the join() is run the program segfaults at glutInit call
What do you think the workerThread.join() method does? Take a look at the answer to this question. So, calling the join method will cause the thread it is called from (main thread) to block and wait until the worker thread has completed. Is that what you want? If you have set up ASIO to run on that main thread, then none of the ASIO I/O socket handlers will be able to execute and thus it will appear to hang because the thread it is on is frozen from the join method. Likewise for the ARToolKit library, if the calls to it have been initiated on this main thread, then it too will appear to freeze because that thread is frozen when the join method is called.
If this is not your problem, then please provide more code.
in the last hours I've struggled with delegates and accessing Windows Forms controls (C++) where I've used this tutorial (the first thread safe method): http://msdn.microsoft.com/en-us/library/ms171728.aspx#Y190
Changing TextBoxes and Labels works perfectly but when I want to show or hide the whole GUI from another thread this fails.
I use the following methode (which is part of the GUI class):
System::Void UI::showUI(boolean value) {
if (this->InvokeRequired) {
SetTextDelegate^ d = gcnew SetTextDelegate(this, &UI::showUI);
this->Invoke(d, gcnew array<Object^> { value });
} else {
if (value == true)
this->Show();
else
this->Hide();
}
}
In the first call the if-clause is true so Invoke is called. But usually the showUI method should be called a second time automatically where the if-clause returns false, but this is not happening. So the GUI is neither shown nor hiden.
Is it necessary to show/hide the GUI with a delegate or can I do it from every possible thread? If a delegate is necessary, why is showUI not executed a second time?
Thanks,
Martin
edit: okay the name SetTextDelegate is not appropriate but this is not the point...
This is a pretty standard case of deadlock, not uncommon with Control::Invoke(). It can only proceed if the UI thread is not busy. Use Debug + Windows + Threads and double-click the Main thread. Look at the call stack to see what it is doing. The typical case is that it is blocking, waiting for the thread to finish the job. That will never happen since the thread can't complete until the Invoke() call returns.
Don't block the UI thread.
Consider using BackgroundWorker, its RunworkerCompleted event is nice to do stuff after the thread completes, removing the need to block.