Why does putting DoEvents in a loop cause a StackOverflow exception? - c#

I was getting a weird error in a legacy application (not written by myself), where I was getting a StackOverflow exception when I changed the date on a calendar.
A simplified version is below. This is the code-behind of a Windows Form containing two controls, a Label called label2 and a calendar called MonthCalendar called monthCalendar1.
I think the idea here was to create a typewriter effect. I am on XP, my colleague on Windows 7 is able to run this ok:
private void monthCalendar1_DateChanged(object sender, DateRangeEventArgs e)
{
const string sTextDisplay = "Press Generate button to build *** Reports ... ";
for (var i = 0; i < 45; i++)
{
label2.Text = Mid(sTextDisplay, 1, i);
System.Threading.Thread.Sleep(50);
//Error on this line
//An unhandled exception of type 'System.StackOverflowException' occurred in System.Windows.Forms.dll
Application.DoEvents();
}
}
public static string Mid(string s, int a, int b)
{
var temp = s.Substring(a - 1, b);
return temp;
}
I can't see the stack trace, all I see is:
{Cannot evaluate expression because the current thread is in a stack overflow state.}
Also, I'm interested in the comments asking why I haven't checked the stack trace of my StackOverflow exception, as it looks like this isn't possible without third party tools at least.
What could be causing this? Thanks

Remember, programs are stack-based. As your program runs, every function call places a new entry on the stack. Every time a function completes, you pop from the stack to see where to go back to, so you can continue the prior method. When a function completes and the stack is empty, the program ends.
It's important to remember the program stack is generous, but finite. You can only put so many function calls on the stack before it runs out of space. This is what happens when we say the stack overflows.
DoEvents() is just another function call. You might put it in a long-running task to allow your program to handle messages from the operating system about user activity: things like clicks, keystrokes, etc. It also allows your program to handle messages from the operating system, for example if the program needs to re-draw it's windows.
Normally, there will only be one or two (or even zero) messages waiting for a DoEvents() call. Your program handles these, the DoEvents() call is popped off the stack, and the original code continues. Sometimes, there may be many messages waiting. If any of those messages also results in code running that again calls to DoEvents(), we are now another level deep in the call stack. And if that code in turn finds a message waiting which causes DoEvents() to run, we'll be yet another level deep. Maybe you can see where this is going.
DoEvents(), used in conjuction with the MouseMove event, is a common source of problems like this. MouseMove events can pile up on you very quickly. This can also happen with KeyPress events, when you have a key that is held down.
Normally, I wouldn't expect a Calendar DateChanged event to have this kind of problem, but if you have DoEvents() somewhere else, or drive another event (perhaps on your label) that in turn updates your calendar, you can easily create a cycle that will force your program to spiral into a stack overflow situation.
What you want to do instead is explore the BackgroundWorder component, or the newer Task and async patterns.
You may also want to read my write-up on DoEvents() for this question:
How to use DoEvents() without being "evil"?

Normally you have a message pump pretty close to the top of the stack. Adding lots of messages isn't ever resulting in a "deep" stack, as they are all processed by a top level pump. Using DoEvents is creating a new message pump at a point deeper in the stack. If one of the messages that you are pumping also calls DoEvents, you now have a message pump even deeper on in the stack. If that message pump has another message that calls DoEvents ... and you get the idea.
The only way for the stack to clear up again is for the message queue to be empty, at which point you start calling back up the stack until you get to the top level message pump.
The problem here is that your code doesn't make it easy. It calls DoEvents a lot in a loop, so it needs to have an idle queue for quite some time to actually get back out of that loop. On top of that, if you happen to have an "active" application that's sending lots of messages to the message queue, possibly lots of monthCalendar1_DateChanged events, or even other events using DoEvents in a loop, or just other events to keep the queue from being empty, it's not particularly hard to believe that your stack would get deep enough to result in an SOE.
The ideal solution of course is to not use DoEvents. Write asynchronous code instead, so that your stack depth never exceeds a constant value.

DoEvents shouldn't use in any case and you don't require substring to archive a TypeWriting effect
Here is the best way I know at the moment:
using System.Threading;
private string text = "this is my test string";
private void button1_Click(object sender, EventArgs e)
{
new Thread(loop).Start();
}
private void loop()
{
for (int i = 0; i < text.Length; i++)
{
AddChar(text[i]);
Thread.Sleep(50);
}
}
private void AddChar(char c)
{
if (label1.InvokeRequired)
Invoke((MethodInvoker)delegate { AddChar(c); });
else
label1.Text += c;
}

Related

Using LocalMessageSender synchronously

We have an application that has a primary window, it can launch multiple other windows, in new browsers. We are using a silverlight application as a coordinating server in the primary window to close all windows that are part of the app, regardless of the way they are opened (we can't guarantee it was via window.open so don't always have a handle to the window in javascript).
On log out, we want to signal all the other windows to perform an auto-save, if necessary, then close down.
So all windows have a silverlight app, they coordinate using localmessagesenders. However, these are asynchronous:
private void ProcessAutosave()
{
foreach (string s in _windows)
{
SendMessage(s, "notify-logout");
}
// code here quoted later...
}
// sendasynch doesn't send until the method terminates, so have to do it in it's own function.
private void SendMessage(string to, string message)
{
var lms = new LocalMessageSender(to);
lms.SendCompleted += new EventHandler<SendCompletedEventArgs>(SenderSendCompleted);
lms.SendAsync(message);
}
Since the ProcessAutosave is called from a javascript onunload event which can't be cancelled, we need this to be synchronous and not complete before we have a response processed from each sub-window so the session state will still be valid etc.
In the SenderSendCompleted we remove items from _windows when they have said they're done.
So I added a loop on the end:
while(_windows.Count > 0) {
Thread.Sleep(1)
}
However, that never terminates, unless I put an iteration counter on it.
Am I the victim of a compiler optimisation meaning the changes in SenderSendCompleted do not affect that while loop, or, have I fundamentally misunderstood something? Or missed something obvious that's staring me in the face?
It sounds like a subtle verson of a race situation due to going sync/async. Couldn't the process in queston also receive notifications from the windows that they have received the message and are shutting down? Once all of the counter messages have been received, then the main app could shut down without the busy wait at the end(?).
I have found a way to work round. However, this does not really "solve" the problem generally, just in my case, which is also only supporting internet explorer.
function WindowCloseEventHandler()
{
var app = // get silverlight app handle...
app.doAutoSave();
var params = 'whatever you need';
var args = new Object();
args.hwnd = window;
window.showModalDialog('blocker.aspx',args,params);
}
function checkAutoSave()
{
var app = // get silverlight app handle...
return app.autosavecomplete();
}
Then in blocker.aspx we display a static "performing logout handlers" type message and do:
function timerTick()
{
if(window.dialogArguments.hwnd.checkAutoSave()) {
window.close();
} else {
setTimeout(timerTick, 500);
}
}
And start the timer on window load.
The child window's silverlight apps are notified to start an autosave, then they notify the parent when they are done. We then poll the parent's status from a modal dialog, which blocks the termination of the WindowCloseEventHandler() which we have wired up to the onclose event of the body.
It's hacky and horrible, but it means silverlight stays asynchronous and we're using a javascript timer so the javascript isn't loading the system.
Of course if the user closes the modal dialogue, there is a potential for issue.

Library works when called in Form1, but not from anywhere else

I have this library http://www.codeproject.com/KB/cs/globalhook.aspx
I've downloaded it and compiled it to DLL.
At first I had a weird problem that it haven't worked in my project, but it did (in the exact same code) worked in the demo project, but it was fixed by applying what the following message said:
http://www.codeproject.com/KB/cs/globalhook.aspx?msg=3505023#xx3505023xx
Note: I'm working with .NET 4, VS 2010 Ultimate
Well, I have a file Form1.cs, which is my main form for my app.
I have other files: Client.cs, Script.cs, Keylogger.cs - no, it's not an evil keylogger - It's for a school presentation about security\antiviruses etc.
Keylogger.cs has one static class and here's the code:
public static class Keylogger
{
static private StreamWriter sw = null;
static private System.Timers.Timer t = null;
static public bool Started = false;
static public void Start(string Location)
{
Started = true;
sw = new StreamWriter(Location, true, Encoding.Default, 1);
HookManager.KeyPress += HookManager_KeyPress;
t = new System.Timers.Timer(3600000);
t.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => sw.WriteLine(Environment.NewLine + "1 HOUR PASSED");
t.Start();
}
static public void Stop()
{
if (!Started)
throw new Exception("Keylogger is not operating at the moment.");
Started = false;
HookManager.KeyPress -= HookManager_KeyPress;
t.Dispose();
sw.Dispose();
}
static private void HookManager_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 8)
sw.Write("{BACKSPACE}");
else
sw.Write(e.KeyChar);
}
}
The Client class isn't static - it manages a TCP connections with a server, and send all received data to Script.RunScript(string scr) (static method).
Well, Script.RunScript should invoke Keylogger.Start(string location) for some input (STARTLOGGING c:\log.txt)
And invoke Keylogger.Stop() for some input (STOPLOGGING)
Well, everything is good, it invokes Start, but it doesn't work.
It does the whole process, (timer, event, streamwriter etc) but when I press something - the whole computer freeze for a couple of seconds and nothing happened (it doesn't even invoke KeyPress) - it happens only the first time. any other time - it simply ignores my keypress.
THE FUNNY THING IS - if I call Start from my mainform (in the ctor, on a button click event) - IT DOES WORK ! without any lag.
I did try different events (MouseDoubleClick, MouseMove) and all had the same problem.
Thank you, Mark !
The delay followed by the UI getting responsive again is a strong sign of the underlying cause of the problem. You see Windows healing itself, noticing that the callback isn't being responsive. It automatically disables the hook.
The hard requirement you probably violate is that the SetWindowsHookEx() call must be made from a thread that pumps a message loop. So that Windows can break in on a keypress and call the callback. That works fine when you called the Start() method from a button click, the Click event runs on the UI thread of your program.
But probably not when you this call is made from a networking event. They tend to run on a threadpool thread. It isn't clear from your snippet, you didn't post the code. The generic fix for a problem like this is using Control.BeginInvoke() to marshal a call from a worker thread to the UI thread. You'll find a good description of it in the MSDN library article as well as many, many answers here at stackoverflow.com
Fwiw, the original code got broken due to changed behavior in the .NET 4 version of the CLR. It no longer fakes the native module for assemblies. The workaround is good enough, it only needs a valid module handle. The actual one doesn't matter since this is not a global hook.
I think your best bet is to not write to the network on UI events, but instead have your logger write to a local file or in-memory database or similar, and then have a timer that periodically writes the content of that message to the server. That way you can both send chunkier messages to the server (improving performance on both machines) as well as have the ability to run the network call on a background thread, which makes the UI feel snappier.

Port scanning using threadpool

I am trying to run a small app that scans ports and checks to see if they are open using and practicing with threadpools. The console window will ask a number and scans ports from 1 to X and will display each port whether they are open or closed. My problem is that as it goes through each port, it sometimes stops prematurely. It doesn't stop at just one number either, its pretty random. For example it I specify 200. The console will scroll through each port then stops at 110. Next time I run it, it stops at 80.
Code
Left out some of the things, assume all variables are declared where they should. First part is in Main.
static void Main(string[] args)
{
string portNum;
int convertedNum;
Console.WriteLine("Scanning ports 1-X");
portNum = Console.ReadLine();
convertedNum = Convert.ToInt32(portNum);
try
{
for (int i = 1; i <= convertedNum; i++)
{
ThreadPool.QueueUserWorkItem(scanPort, i);
Thread.Sleep(100);
}
}
catch (Exception e)
{
Console.WriteLine("exception " + e);
}
}
static void scanPort(object o)
{
TcpClient scanner = new TcpClient();
try
{
scanner.Connect("127.0.0.1",(int)o);
Console.WriteLine("Port {0} open", o);
}
catch
{
Console.WriteLine("Port {0} closed",o);
}
}
}
If this is the entire code, then the error is probably caused by you just falling through to the end of main() without waiting for all your thread pool threads to finish. The ThreadPool threads are all aborted once your main thread exits after falling through main().
Try removing the Thread.Sleep(100) (it is not needed, this is the wrong way, you'd never know for how long to sleep for and it partially defeats the purpose of using a ThreadPool in the first place) and you will probably not even check a single port!
Instead you could have each of your worker threads set an event and use WaitAll in main for all events to finish. See http://msdn.microsoft.com/en-us/library/3dasc8as.aspx for an example.
Edit:
Thinking this through, the solution referenced at the link above is probably less than ideal for you as well (it might involve having to allocate an array of 65000 events, this would be excessive). In .net 4 you could use a CountdownEvent like this:
Sorry, I gotta run, but check this example http://msdn.microsoft.com/en-us/library/system.threading.countdownevent.aspx and let us know when you have further questions, I'm sure someone can and will elaborate or suggest a better solution and a solution more suitable for .net3
What OS? Don't forget, different versions of XP have tcp connection limits, while you may also be triggering anti DDOS protection as well.
Also, your logic is flawed. Just because TcpClient.Connect excepted, doesn't mean the port is closed. You should be capturing and displaying that exception's details as I imagine it will offer you greater insight into why your code is stopping. Keep in mind, its possible to throw a SocketException or SecurityException as well.
Concerning the threading part, you could consider using the Task Parallel Library (TPL) instead of directly accessing the ThreadPool.
IMHO it offers a more simple use and a more intuitive/readable syntax.

C# Error on Close

When I close my C# application, I am getting the a windows sound that indicates an error. However, when I debug through the close process, I get all the way back up into the Program class...
It gets past Application.Run(..), exits the static void Main() function, and then makes the error noise.
Other than the noise there is nothing indicative of an error. I don't even know where to begin looking! Any ideas?
One thing that you could to in order to maybe get some information is to hook up event listeners for the AppDomain.UnhandledException and Application.ThreadException events. It's a long shot, but may provide some info. You could add the following in the beginning of the Main function to set them up, and have them show any exception info in a message box:
static void Main()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(delegate(object sender, UnhandledExceptionEventArgs e)
{
MessageBox.Show(e.ExceptionObject.ToString());
});
Application.ThreadException += new ThreadExceptionEventHandler(delegate(object sender, ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.ToString());
});
// run your app
}
It only happens when you close your app or does it happen when you close any app?
My first thought would be that someone changed your windows sound scheme and set the close program sound to mess with you :).
Something is going wrong in the cleanup, that could be very hard to find. There are two ways to attack this:
Enhance the chances of detecting it while you're still in control (in Main) by wrapping everything in your Main in a try/catch and add some code after the Application.Run to get as much of the cleanup going as possible. A few things I can think of:
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(1000);
GC.Collect();
GC.WaitForPendingFinalizers();
Collect at least 2 times, maybe more. In the same spirit, add a few Application.DoEvents() in the OnClosing of the MainForm.
The other approach is more dependent on your code, to take a stab in the dark: look for all static fields/properties you can set to null and Disposable objects you can Dispose deterministically on Exit.
And all this in combination with Fredrik Mörks suggestion for the UnhandledException event.
Do you have any code that raises custom events? Could these processes still be running when the app tries to close in real-time?
Do you have any custom Dispose code that could be running at time of close?

.NET Windows Service with timer stops responding

I have a windows service written in c#. It has a timer inside, which fires some functions on a regular basis. So the skeleton of my service:
public partial class ArchiveService : ServiceBase
{
Timer tickTack;
int interval = 10;
...
protected override void OnStart(string[] args)
{
tickTack = new Timer(1000 * interval);
tickTack.Elapsed += new ElapsedEventHandler(tickTack_Elapsed);
tickTack.Start();
}
protected override void OnStop()
{
tickTack.Stop();
}
private void tickTack_Elapsed(object sender, ElapsedEventArgs e)
{
...
}
}
It works for some time (like 10-15 days) then it stops. I mean the service shows as running, but it does not do anything. I make some logging and the problem can be the timer, because after the interval it does not call the tickTack_Elapsed function.
I was thinking about rewrite it without a timer, using an endless loop, which stops the processing for the amount of time I set up. This is also not an elegant solution and I think it can have some side effects regarding memory.
The Timer is used from the System.Timers namespace, the environment is Windows 2003. I used this approach in two different services on different servers, but both is producing this behavior (this is why I thought that it is somehow connected to my code or the framework itself).
Does somebody experienced this behavior? What can be wrong?
Edit:
I edited both services. One got a nice try-catch everywhere and more logging. The second got a timer-recreation on a regular basis. None of them stopped since them, so if this situation remains for another week, I will close this question. Thank you for everyone so far.
Edit:
I close this question because nothing happened. I mean I made some changes, but those changes are not really relevant in this matter and both services are running without any problem since then. Please mark it as "Closed for not relevant anymore".
unhandled exceptions in timers are swallowed, and they silently kill the timer
wrap the body of your timer code in a try-catch block
I have seen this before with both timer, and looped services. Usually the case is that an exception is caught that stops the timer or looping thread, but does not restart it as part of the exception recovery.
To your other points...
I dont think that there is anything "elegant" about the timer. For me its more straight forward to see a looping operation in code than timer methods. But Elegance is subjective.
Memory issue? Not if you write it properly. Maybe a processor burden if your Thread.Sleep() isn't set right.
http://support.microsoft.com/kb/842793
This is a known bug that has resurfaced in the Framework more than once.
The best known work-around: don't use timers. I've rendered this bug ineffective by doing a silly "while (true)" loop.
Your mileage may vary, so verify with your combination of OS/Framework bits.
Like many respondents have pointed out exceptions are swallowed by timer. In my windows services I use System.Threading.Timer. It has Change(...) method which allows you to start/stop that timer. Possible place for exception could be reentrancy problem - in case when tickTack_Elapsed executes longer than timer period. Usually I write timer loop like this:
void TimeLoop(object arg)
{
stopTimer();
//Do some stuff
startTimer();
}
You could also lock(...) your main loop to protect against reentrancy.
Interesting issue. If it is truly just time related (i.e. not an exception), then I wonder if you can simply periodically recycle the timer - i.e.
private void tickTack_Elapsed(object sender, ElapsedEventArgs e)
{
CheckForRecycle();
// ... actual code
}
private void CheckForRecycle()
{
lock(someLock) {
if(++tickCount > MAX_TICKS) {
tickCount = 0;
tickTack.Stop();
// re-create timer
tickTack = new Timer(...);
tickTack.Elapsed += ...
tickTack.Start();
}
}
}
You could probably merge chunks of this with the OnStart / OnStop etc to reduce duplication.
Have you checked the error logs? Maybe you run out of timers somehow. Maybe you can create just one timer when you initialize the ArchiveService and skip the OnStart stuff.
I have made exactly the same as you in a few projects but have not had the problem.
Do you have code in the tickTac_Elapsed that can be causing this? Like a loop that never ends or some error that stops the timer, using threads and waiting for ending of those and so on?

Categories