views:

872

answers:

15

I got a thread that is just banishing.. i'd like to know who is killing my thread and why.

It occurs to me my thread is being killed by the OS, but i'd like to confirm this and if possible to know why it's killing it.

As for the thread, i can assert it has at least 40 min of execution before dying, but it suddenly dies around 5 min.

public void RunWorker()
{
    Thread worker = new Thread(delegate()
    {
        try
        {
            DoSomethingForALongLongTime();
        }
        catch(Exception e)
        {
           //Nothing is never logged :(
           LogException(e);
           throw e;
        }
    });

    worker.IsBackground = true;
    worker.SetApartmentState(System.Threading.ApartmentState.STA);
    worker.Start();
}

EDIT: Addressing answers

  • Try/Catch Possible exceptions:
    It's implemented and it catches nothing :(
  • Main Thread dying:
    This thread is created by the web server, which continues to run
  • Work completion:
    The work is not completed, as it finally affects the database, i can check whether it's done or not when the thread dies.

Having thought of these things brought me to this question, who is killing my threads??

ps. It's not Lady Goldent in the living room with the candle stick :)

+12  A: 

Your thread probably just threw an exception. Try putting a try/catch block around DoSomethingForALongLongTime and see what it picks up.


Update: I didn't notice before that you were starting this from a web server. That can be a very bad idea. In particular, is the separate thread using any information derived from HttpContext.Current? That would include Request, Response, Session, etc., as well as any information from the page.

This is bad because these things only last as long as the request lasts. Once the request is over, they become invalid, to say the very least.

If you need to kick off a long-running thread from within a web application or web service, then you should create a simple Windows Service and host a WCF service within it. Have the web page then send all the information needed to perform the task to the service. The service can even use MSMQ as a transport, which will ensure that no messages are lost, even if the service gets busy.

John Saunders
implemented, no luck :(
mcabral
Perhaps your thread did something completely illegal and died to segmentation violation (which wouldn't show up as an exception). You might create a signal handler which raises an error flag, which you could then check.
Justin
@Justin: he's running .NET. There's nothing so completely illegal that there would be no exception. A "segment violation" cannot occur, unless working with unmanaged code.
John Saunders
@Downvoter: If you don't say why you downvoted, then nobody cares what you think.
John Saunders
+3  A: 

The process might be terminating. That would be what worker.IsBackground = true; is designed to do, kill your thread when the main thread exits.

Jimmy
+1  A: 

If checking for an exception doesn't show anything useful, get your thread code to write to a log file at key points. You'll then be able to see exactly when it stops working and hopefully why.

ChrisF
Had the same ideia. Maybe some condition is finalizing the thread, so...
Bruno Brant
+3  A: 

A background thread will only run as long there are foreground threads runnnig.

As soon that all foreground threads end, any background thread still running will aborted.

Alfred Myers
+4  A: 

I don't know the answer, but some thoughts:

  • Could it be throwing an exception? Have you tried putting a try/catch around the DoSomethingForALongLongTime() call?
  • Are there any points where it exits normally? Try putting some logging on them.
  • Do you get the same behaviour in and out of the debugger? Does the output window in the debugger provide any hints?

UPDATE

You said:

This thread is created by the web server, which continues to run

If the thread is running inside asp.net then it may be that the thread is being killed when the asp.net worker process recycles, which it will do periodically. You could try turning off worker process recycling and see if that makes any difference.

Andy Johnson
Plausible. A good summary is available here: http://bluedragon.blog-city.com/why_might_a_net_web_application_app_domain_restart_the_reaso.htm
Hans Passant
+2  A: 

A simple answer would be: "The killer doesn't leave a name card" ;)

  • If your thread is hosted in IIS, probably the thread is killed by the app pool process which recycles. The server might continue running but the process which hosts your item is stopped untill a new request fires everything up again.
  • If your thread is hosted in an executable, the only way it can be killed is by killing the thread yourself, throwing an exception in the thread or terminating the host process

Hope this helps.

Jeroen Landheer
+2  A: 

You can try to increase executionTimeout value of configuration\system.web\httpRuntime in web.config (default value is 110 seconds in .NET 4.0 and 90 in corresponds to http://msdn.microsoft.com/en-us/library/e1f13641.aspx). You can try to change it dynamically Server.ScriptTimeout = 300 (see http://www.beansoftware.com/ASP.NET-Tutorials/Long-Operations.aspx). It this parameter will not helps, then I think you have a problem other as thread recycling from IIS. How you can see default value of this parameter is much less as typical live time of your thread. I think, that your problem has another nature, but to be sure...

Why you set apartment state for the thread? Which COM objects you use in the working thread? Do you have an unmanaged code which do the most of work where you can also insert some code? I think you should have more information about SomethingForALongLongTime to be able to solve the problem.

And one more a little suggestion. Could you insert a line of code after calling SomethingForALongLongTime(); to be sure, that SomethingForALongLongTime not end without an exception?

UPDATED: To be absolutely sure that your thread will be not killed by IIS, you can try to create a process which do SomethingForALongLongTime(); instead of using threads.

Oleg
A: 

It could be throwing one of the various uncatcheable exceptions including Stack Overflow or Out of Memory. These are the hardest exceptions to track down.

What does memory consumption look like while this thread is running? Can you use a memory profiler on it to see if it's out of control? Can you add some logging in inner loops? If you have a recursive method, add a counter and throw an exception if it recurses an impossible number of times. Are you using large objects that could be causing large object heap fragmentation (causes out of memory errors even when you aren't really out).

Hightechrider
+2  A: 

A potential way to get more information: attach a debugger and break on thread termination. Depending on how your thread is being terminated, this might not work.

  1. Download Debugging Tools for Windows if you don't already have it
  2. Run windbg.exe, attach to your process
  3. Break into windbg, type sxe et to enable breaking on thread exit
  4. When the debugger breaks, inspect the state of the system, other threads, etc.
  5. To get the managed stack, load sos.dll (.loadby sos mscorsvr, .loadby sos mscorwks, or .loadby sos clr should work), then run !clrstack (see !help for other sos commands)

If you get a lot of noise from other threads exiting, script windbg to continue after breaking if it's not the thread ID you care about.

Edit: If you think the thread is being terminated from within your process, you can also set a breakpoint on TerminateThread (bp kernel32!TerminateThread) and ExitThread (bp kernel32!ExitThread) to catch the stack of the killer.

Chris Schmich
If someone is calling Thread.Abort() on your thread, then you might try catching the special exception ThreadAbortException, to know about it. This won't tell you who, but it will tell you when.
Justin
A: 

You should instrument DoSomethingForALongLongTime() with lots of debug logs, so you can find out at what spot does the code stop executing. Or attach a debugger and break on all first chance exceptions.

Chris O
A: 

Can you run this as part of the Application, and not tied to any specific request, then have it called from a Request?

Dean J
+1  A: 

When you call RunWorker(), you can add a reference to your thread to a list. Once you have detected that your thread has died, you can inspect the state of the thread, perhaps it will reveal how it died. Or, perhaps it hasn't died, its just waiting on some resource (like the connection to the database).

List runningThreads = ...
public void RunWorker() {
    Thread worker = new Thread(delegate()
    ..
    runningThreads.add(worker);
    worker.Start();
}

public void checkThreads() {
 for (Thread t : runningThreads) {
   Console.WriteLine("ThreadState: {0}", t.ThreadState);
 }
}
Justin
A: 

use AsyncTasks to achieve your long running work in asp.net

Tim Mahy
+5  A: 

Various people (including myself, here) pointed out that hosting a long-running thread in IIS is a bad idea. Your thread will being running inside an IIS 'worker process'. These processes are periodically terminated (recycled) by IIS, which will cause your thread to die.

I suggest that you try turning-off IIS worker process recycling to see if that makes a difference. You can find more information here.

Andy Johnson
This looks very promising; it fits all symptoms. I'm surprised though, that IIS can migrate all thread state to a sub-process without his DoStuffForLongTime() function not even being aware. Is it shared memory?
Justin
because this is background thread it is not have to run forever. once the host's last foreground thread is ended everything else goes south... I cant tell whether you can trick IIS but I'd simply change to foreground and test.
Bobb
A: 

Try use app domain UnhandledException event: http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx

it may give you some information if you miss some exceptions

Kamarey