How to protect main-thread from errors caused by children (SBCL) - multithreading

I am currently playing with sb-thread API, provided by SBCL, wondering what happens if an error is thrown inside a started thread and how to ensure that only that process is affected (and dies), and no other process is, as apparently the debugger will be entered even though not the main thread throws an error.
* (handler-case
(sb-thread:join-thread (sb-thread:make-thread #'(lambda()
(error 'simple-error))))
(sb-thread:join-thread-error (err)
(sb-thread:thread-error-thread err)
(FORMAT t "allemeineentchen~%")))
(A SIMPLE-ERROR was caught when trying to print *DEBUG-CONDITION* when entering
the debugger. Printing was aborted and the SIMPLE-ERROR was stored in
SB-DEBUG::*NESTED-DEBUG-CONDITION*.)
;after this sbcl just yields until str-c enters the debugger
My suggestion would be to make each thread function body starting with an (handler-case (body) (error (err) err) but this seems awfully non-standard/malpractice and only works with threads whose function body are created by me, and I am not sure that this will, in every case, prevent entering the debugger.
Is there some guideline/(unofficial)standard concerning this topic?

You need to be very clear about what is being signalled and what is being handled (and where): First, what error condition are you trying to handle? When you call #'error in your thread with 'simple-error, that is a problem, because sbcl will not be able to print the error which you have signalled, but otherwise things are working as they should. If I do this:
(handler-case
(sb-thread:join-thread
(sb-thread:make-thread #'(lambda()
(error "simple error"))))
(simple-error (c)
c)
(sb-thread:join-thread-error (c)
(sb-thread:thread-error-thread c)))
Sbcl correctly enters the debugger for the unhandled simple-error, however the join-thread-error which gets signalled after I use the abort restart from the debugger does get handled, and I think that is what you were asking about:
simple error
[Condition of type SIMPLE-ERROR]
Restarts:
0: [ABORT] Abort thread (#<THREAD RUNNING {DABCAD1}>) 0 ==> #<SB-THREAD:THREAD ABORTED {DABCAD1}>
Edit: I am adding this after reading Sim's comment:
If you just want to ignore any errors in the thread then do that:
(sb-thread:join-thread
(sb-thread:make-thread #'(lambda() (ignore-errors
(error "simple error")))))

Related

node option: making it quite when an error is thrown

is there a node cli option that lets it not print an error?
For example, I'd like the command below not to print an uncaught exception, even if it occurs. But I don't simply want to catch it in the code. If there's no exception or error, then it should print (if message to print exists) what it's intended to.
$ node --quiet-on-err(?) this-script-throws-err.js
Thanks,
This is a good use case for redirection (assuming you're using a platform that has /dev/null): node this-script-throws-err.js 2/>dev/null.
Wouldn't catching all uncaught exception work for you? Add this to the code. This is a process wide event handler that gets called whenever an uncaught exception is found.
process.on('uncaughtException', (exception) => {
// handle or ignore error
});

Is there a Node.js equivalent of Java UncaughtExceptionHandler?

I had some problematic code in a Node.js application which caused an error (manifested as strange output) but not a total crash. It displayed nothing in the console to indicate an error occurred, and I only identified the root cause by a lot of trial and error in commenting out lines selectively.
To save time in future, is there anything like Java's UncaughtExceptionHandler in Node that will catch anything that's causing errors and display them in the console so I can pinpoint bug(s) immediately?
Yes. You can listen for that event by doing this
process.on('uncaughtException', (err) => {
});
It will override the default behaviour of exiting.
Documentation

Nodejs exit on error, shoud prevent or not?

I'm using Nodejs in my windows machine. the question is Nodejs always terminate process on errors e.g. empty Mysql insert statement.
So in production time, and without manual error handling, how can prevent NodeJs exit?
example code:
app.post('/api/accounts',function(req,res){
pool.getConnection(function(error,connection){
connection.query('insert into accounts set ?',req.body,function(err,results){
if (err) {
throw err ;
} else {
console.log(results) ;
}
});
});
console.log('post received') ;
console.log(req.body);
});
Imagine i post an empty req.body.
nodejs will exit on error like this
\node_modules\mysql\lib\protocol\Parser.js:77
throw err; // Rethrow non-MySQL errors
^
Is it possible to configure something in node to just show errors but don't exit?
It's not really a good thing to be continuing execution after a unhandled exception has been thrown by the interpreter (as Ginden said in his answer) - anything could happen and it could prove to be a mistake later, any sort of hole could easily be opened by stopping the process from cleaning up after something went so unexpectedly wrong in your code.
You could sensibly add a event handler for unhandledException like the answer by Ginden points out, however, it seems you're using express and it would make much more sense actually handling the error with middleware when it happens, instead of using throw as per your code.
Replace throw err; with return next(err); and that should mean the request will fall through to the next set of middleware, which should then handle the error, do some logging, tell the user, whatever you want it to do.
app.use(function(err, req, res, next) {
// Maybe log the error for later reference?
// If this is development, maybe show the stack here in this response?
res.status(err.status || 500);
res.send({
'message': err.message
});
});
Don't try to prevent process shutdown. If error was thrown, anything could happen.
Warning: Using 'uncaughtException' correctly
Note that 'uncaughtException' is a crude mechanism for exception handling intended to be used only as a last resort. The event should not be used as an equivalent to On Error Resume Next. Unhandled exceptions inherently mean that an application is in an undefined state. Attempting to resume application code without properly recovering from the exception can cause additional unforeseen and unpredictable issues.
Exceptions thrown from within the event handler will not be caught. Instead the process will exit with a non zero exit code and the stack trace will be printed. This is to avoid infinite recursion.
Attempting to resume normally after an uncaught exception can be similar to pulling out of the power cord when upgrading a computer -- nine out of ten times nothing happens - but the 10th time, the system becomes corrupted.
Domain module: don't ignore errors.
By the very nature of how throw works in JavaScript, there is almost never any way to safely "pick up where you left off", without leaking references, or creating some other sort of undefined brittle state.
The safest way to respond to a thrown error is to shut down the process. Of course, in a normal web server, you might have many connections open, and it is not reasonable to abruptly shut those down because an error was triggered by someone else.
The better approach is to send an error response to the request that triggered the error, while letting the others finish in their normal time, and stop listening for new requests in that worker.

Why seems my object to become NULL from one line to the next? - Could it be a hardware thing?

First thing to say: I program in a relatively unknown language: Blitzmax, which is a object oriented Basic dialect.
My problem is the following:
I wrote a debugmanager which runs in an own thread. So from every position in the program (it will be a game) you can add debug- or errormessages to the manager's queue.
In its own thread, it will fetch the messages from the queue and process them by writing them into a file and (if the message has the current chosen Debuglevel, Debugcategory and outputcategory, which are just enums) write it to the console.
Now I tested the program on three systems: My desktop PC which has Windows 8 as OS, my own laptop which has Windows 7 and the laptop of a friend which also has windows 7.
On my PC and my friend's laptop everything is fine.
But on my own laptop I get, nearly everytime, an "EXCEPTION_ACCESS_VIOLATION" Error while the manager is processing the messages.
Sometimes the program just runs fine, but most of the time it breaks down with this error.
Even in debugmode no line or stacktrace is shown which made it very hard to debug.
I broke all needed classes down to a minimum of attributes and functionality to make it easier to find the problem.
Now the queue is just a list (which is natively build in in Blitzmax) and the message just has one attribute which is a string.
Also the debugmanager only writes the message into the console without passing it to the process method which would write it to a file etc.
So the code which is actually needed is the following.
This is the message:
Type TThreadsafeMessage
Field complete_String:String
Method New_ThreadsafeMessage:TThreadsafeMessage(actual_Message:String, from_File:String, debugCategory:TDebugCategory_Enum, ..
debugLevel:TDebugLevel_Enum, outputCategory:TOutputCategory_Enum, from_Class:String = "", from_Method:String = "")
'Just create the string from the parameters.
Self.complete_String = actual_Message + " | " + from_File + "/" + from_Class + "/" + from_Method
Return Self
End Method
Method ToString:String()
'Just return the string attribute:
Return Self.complete_String' out_String
End Method
Method toString_Formatted_For_File:String()
Return Self.ToString()
End Method
Method toString_Formatted_For_Console:String()
Return Self.ToString()
End Method
End Type
This is the queue:
Type TThreadsafeQueue
'Predefined list.
Field list:TList
Method New()
Self.list = New TList
End Method
Method isEmpty:Byte()
Return Self.list.IsEmpty()
End Method
Method enqueue(to_Enqueue:Object)
'Add object to list
Self.list.AddLast(to_Enqueue)
End Method
Method dequeue:Object()
Return Self.list.RemoveFirst()
End Method
End Type
Here is the method which adds messages to the debugmanager:
Function enqueueMessage(message_To_Enqueue:TThreadsafeMessage)
'Test message for null pointer.
If(message_To_Enqueue = Null) Then
Throw New TNullpointer_Exception.NewException("'message_To_Enqueue' is NULL.", "TDebugmanager.bmx", ..
"TDebugmanager", "enqueueMessage")
EndIf
'Lock mutex for threadsafety.
LockMutex(TDebugmanager.getSingleton_Instance().queue_Mutex)
'Enqeue message in the queue
TDebugmanager.getSingleton_Instance().message_Queue.enqueue(message_To_Enqueue)
'Tell the update thread there is a message
SignalCondVar(TDebugmanager.getSingleton_Instance().sleep_ConditionVariable)
'Free the mutex for update thread.
UnlockMutex(TDebugmanager.getSingleton_Instance().queue_Mutex)
End Function
Now here is the (currently smaller) update function of the debugmanager:
Function _update:Object(thread_Object:Object)
'Do this over and over till the queue is empty AND the debugmanager is shut down
Repeat
Local message_To_Process:TThreadsafeMessage = Null
'Lock mutex for thread safety
LockMutex(TDebugmanager.getSingleton_Instance().queue_Mutex)
'Queue epmty...
If(TDebugmanager.getSingleton_Instance().message_Queue.isEmpty()) Then
'... Wait for a signal from the main thread
WaitCondVar(TDebugmanager.getSingleton_Instance().sleep_ConditionVariable, ..
TDebugmanager.getSingleton_Instance().queue_Mutex)
Else
'...Get the next message from the queue.
message_To_Process = TThreadsafeMessage(TDebugmanager.getSingleton_Instance().message_Queue.dequeue())
EndIf
'Unlock the mutex.
UnlockMutex(TDebugmanager.getSingleton_Instance().queue_Mutex)
'Check if the message is NULL.
If(message_To_Process = Null) Then
Throw "Got null message from queue."
EndIf
'Actually the _processMessage method is used. But for debugging
'it is commented out.
' TDebugmanager.getSingleton_Instance()._processMessage(message_To_Process)
'Write the message to the console.
'HERE is the error.
'See in the following description under the code section.
DebugLog("Message processed: " + message_To_Process.complete_String)
Until TDebugmanager.isFinished()
End Function
So at the position where it says in the update function 'HERE is the error.' the problem is the following: If this line is commented out or deleted, the program runs fine on my laptop and no error occures.
But if this line is there, the error occures most of the times.
An "EXCEPTION_ACCESS_VIOLATION" is thrown for example when: A stackoverflow occures somewhere. Or when you try to access to a NULL object.
Actually everything which tries to read or write from forbidden memory.
The really strange thing is: Only a few lines earlier, I check if the message which I got from the queue is NULL.
It should throw an error, as you can see.
But it never does.
Has anyone seen such a behaviour before?
I cannot explain that.
As I said: Debugging is really hard in this case. I could just break it down to smaller classes and finally the code you see here.
I also cannot just go step for step through the program with the debugger because then no error occures.
Can someone maybe think of something which can cause the error in this moment?
I know, this is much code, but I could not make it any shorter.
You are basically writing concurrently to a stream. If DebugLog is not reentrant (eg. there's some static buffer used internally), you will get random access violation. On faster machine, that could be perhaps avoided because contention will happen at the message queue, hence each thread will have the time to do a full loop on its own.
The solution is to lock the use of that function (you may want to make a function wrapper which implement that locking independently of the queue processing).
The problem was the following:
When I tried to debug the program a little bit more, sometimes the debugger kicked in and showed me where the debugger thought the error occured. It didn't occure there, but I was able to use the step-In function of the debugger.
The result was: It jumed into a library which is used for network methods. I do not use this library anywhere in the project.
So I tried a little bit further and the actual solution was: Deinstall Blitzmax and reinstall it. Now everything works fine.
Seems as if the linker was broken somehow.

Possible causes of "EOSError 1400 - Invalid window handle"

I have a problem.
I have a VCL application using a thread. This thread does some calculations and calls a MainForm's method through Synchronize(). It all works just fine, I have a "Start" button, which creates and runs the thread and a "Stop" button which stops and frees it. No errors, no nothing.
But for some reason when I close the application and I've run the thread I get a EOSError 1400 - Invalid window handle. I've breakpointed the OnClose procedure and the only thing I do there is saving an ini file, no error in that, when I trace further (using F7), I get to the very end (Application.Run; end.), after "calling" the end. I get the error, so there is no specific line of code raising it.
I hope the question is somewhat clear and I hope it's solvable, because just ignoring the error seems a bit unclean.
Thanks inb4
ANSWER
This error occured to me when the Execute method of a thread was called, it looked like this:
procedure TRunThread.Execute;
var (...)
begin
while not Terminated do begin
(...)
MainForm.Memo1.Lines.Add('Some text'); // Even though this call worked fine during
//the application running, it caused errors on shutting the app down.
// For acccessing GUI elements, it's necessary to use Synchronize()
(...)
end;
end;
A possible reason is some unsynchronized access to GUI from the thread. You said that the thread does not do it, but without seeing the TRunThread.Execute source code that looks like the best guess.
I had the same problem, error code 5 Access is denied. This turned out to related to a thread started to test an internet connection on an embedded panel (using BeginThread). If the user exits the form (which is testing the internet connection) immediately after displaying the form, the AV occurs.
On my development PC, the internet connection test was successful...and so fast I never saw the problem! After struggling for several hours, I finally tracked it down to this thread and reproduced it by disconnecting my network cable.
The solution was straightforward: When exiting the form (eg. in the FormDestroy event) ensure the thread is definitely not running before continuing.

Resources