When I spawn a thread with Thread.new{} it looks like any exception that happens in that thread never sees the light of day, and the app just quietly ignores it
Normally, threads are isolated from each other, so exception in one won't terminate the whole application.
But, although I never used them, Thread class has several abort_on_exception methods, even with some examples. They should do what you want.
http://corelib.rubyonrails.org/classes/Thread.html
Adding to Nikita's answer, you can also trigger the exception by calling thread.join on the thread you've generated.
If you run the program with the debug flag on (ruby -d), then you'll also abort when an unhandled exception is raised in a thread.
Related
Can a Windows thread suspend itself with SuspendThread()?
I can awake it from another one but, can it call SuspendThread(GetCurrentThreadId())?
It seems this is possible, but with a slight alteration (see the cygwin mailing list discussing this here):
SuspendThread(GetCurrentThread());
I also found MSDN saying a thread should only suspend itself, but it doesn't make it clear for me. I quote (from here, emphasis mine):
This function is primarily designed for use by debuggers. It is not intended to be used for thread synchronization. Calling SuspendThread on a thread that owns a synchronization object, such as a mutex or critical section, can lead to a deadlock if the calling thread tries to obtain a synchronization object owned by a suspended thread. To avoid this situation, a thread within an application that is not a debugger should signal the other thread to suspend itself. The target thread must be designed to watch for this signal and respond appropriately.
Yes, you can use SuspendThread on current thread. Good read on the topic.
As a method of creating reusable threads for work tasks without the overhead of create and terminate tasks, suspend and resume thread could be used to quiesce a thread at the end of the task. When work is dispatch to the thread, resume it.
I have a program that have 2 threads running at the same time. Every method is surrounded with a try and catch. If one of the threads creates an exception will it stop the other thread from working as well?
Thanks
No. It will only stop the current thread. The other thread will continue working.
Exceptions are being stored in the stack of each thread.
You can pass exception information between threads using asynchronous delegates:
Catching an exception thrown in an asynchronous callback
I am using Ruby 1.9.2.
I have a thread running which makes periodic calls to a database. The calls can be quite long, and sometimes (for various reasons) the DB connection disappears. If it does disappear, the thread just silently hangs there forever.
So, I want to wrap it all in a timeout to handle this. The problem is, on the second time through when a timeout should be called (always second), it still simply hangs. The timeout never takes effect. I know this problem existed in 1.8, but I was lead to believe timeout.rb worked in 1.9.
t = Thread.new do
while true do
sleep SLEEPTIME
begin
Timeout::timeout(TIMEOUTTIME) do
puts "About to do DB stuff, it will hang here on the second timeout"
db.do_db_stuff()
process_db_stuff()
end
rescue Timeout::Error
puts "Timed out"
#handle stuff here
end
end
end
Any idea why this is happening and what I can do about it?
One possibility is that your thread does not hang, it actually dies. Here's what you should do to figure out what's going on. Add this before you create your worker thread:
Thread.abort_on_exception = true
When an exception is raised inside your thread that is never caught, your whole process is terminated, and you can see which exception was raised. Otherwise (and this is the default), your thread is killed.
If this turns out not to be the problem, read on...
Ruby's implementation of timeouts is pretty naive. It sets up a separate thread that sleeps for n seconds, then blindly raises a Timeout exception inside the original thread.
Now, the original code might actually be in the middle of a rescue or ensure block. Raising an exception in such a block will silently abort any kind of cleanup code. This might leave the code that times out in an improper state.
It's quite difficult to tell if this is your problem exactly, but seeing how database handlers might do a fair bit of locking and exception handling, it might be very likely. Here's an article that explains the issue in more depth.
Is there any way you can use your database library's built-in timeout handling? It might be implemented on a lower level, not using Ruby's timeout implementation.
A simple alternative is to schedule the database calls in a separate process. You can fork the main process each time you do the heavy database-lifting. Or you could set up a simple cronjob to execute a script that executes it. This will be slightly more difficult if you need to communicate with your main thread. Please leave some more details if you want any advice on which option might suit your needs.
Based on your comments, the thread is dying. This might be a fault in libraries or application code that you may or may not be able to fix. If you wish to trap any arbitrary error that is generated by the database handling code and subsequently retry, you can try something like the following:
t = Thread.new do
loop do
sleep INTERVAL
begin
# Execute database queries and process data
rescue StandardError
# Log error or recover from error situation before retrying
end
end
end
You can also use the retry keyword in the rescue block to retry immediately, but you probably should keep a counter to make sure you're not accidentally retrying indefinitely when an unrecoverable error keeps occurring.
Once, during testing, my C++Builder / Delphi application raised an uncaught exception in a background worker thread. EurekaLog caught the exception and sent an error report, as I expected, and everything appeared to be okay.
However, when I closed the application's main window, something remained running in the background, because the application was still listed in the task manager (and still had resources open).
I've tried to duplicate this problem, by deliberately introducing various bugs in the background worker thread, but I can't.
What could cause a thread and application to remain running like this, even after the main window has closed (and, presumably, PostQuitMessage has been called)?
How can I ensure that the application always cleanly shuts down?
The first rule is that threads main executor methods should be written so that they can be signalled and shut down properly, and the second rule is that you shouldn't just shut down your app's main thread first, and then hope that the other threads shut down in their own time, to be safe, you should signal all the background threads to stop, wait for that shutdown to complete, and THEN shutdown your main thread. A minimal THREAD example:
procedure TMyThread.Execute;
begin
Init;
while not Terminated do
OneWorkItem; // inside OneWorkItem, you ALSO need to check for Terminated
end;
A minimal main form/main-thread example:
procedure TMyMainForm.CheckAndShutdown;
begin
if FPendingShutdownFlag then
if AllBackgroundThreadsTerminated then
Self.Close;
end;
You could set FPendingShutdownFlag and have the function above called from the application idle processing loop. When you have the user click the main form FormClose, if AllBackgroundThreadsTerminated returns false, set CanClose to false, and set the FPendingShutdownFlag := true instead.
If you make an endless loop (while true), the application does not shut down cleanly, even if it looks like that to you. Somehow, the application is terminated, and the running threads may just suddenly go away quietly, or they may deadlock or otherwise fail on you, as they may be using resources in thread 2 that you are busy freeing in thread 1.
You may have one or more intentional race conditions because you might not have written your thread execute method to be interruptable, or you may start the closing of the main application thread and the VCL and its objects, before you are sure that your background threads are completely shut down.
Are you sure that worker thread terminated, and main thread is not waiting for it to finish?
I've noticed that if I create an NSURLConnection and fire the request, all is well. My delegate methods get called and the last delegate method get's called well after the code block invoking the connection completes. Great.
That leads me to believe the connections are asynchronous which implies that they're multi-threaded. Is that correct? Could they be asynchronous but in the same thread? No, that's crazy - right?
But, in every example I've seen using an NSOperation, NSURLConnections are always scheduledInRunLoop after which [runLoop runMode ...] is invoked in a while loop.
Can someone explain exactly what is happening here? It seems to me that the first case requires spawning secondary threads but no manual invocation of the run loop (on those threads) while NSOperation (in a new thread) does require manual invocation of the run loop.
Why is no manual invocation required for the first case?
NSURLConnection does spawn a single background thread to manage all instances of itself, but this is generally irrelevant to the caller, since the delegate calls are made on whatever thread owns the runloop the connection was scheduled in. (This fact turned out to be very relevant to me recently, but these things really only come up when dealing with insane crashers in multi-threaded apps.)
For more caller-relevant details, you should look at the docs for -[NSURLConnection scheduleInRunLoop:forMode:]. It explains how to manually handle scheduling and unscheduling, and how NSURLConnections behave in a multi-threaded environment.
If you are unclear on how run loops work and how they perform asynchronous actions without requiring additional threads, you should read Run Loops in the Threading Programming Guide. This is a very important topic for moving to more advanced Cocoa development.
Because the main thread already has a run loop, I'd imagine.
If you want to run NSURLConnection in another thread, you should create a run loop like this in your thread's main method:
while (!finished)
{
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}