Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread doesn't terminate when main thread finishes

I have a weird issue:

In my C# app, I am creating another thread, like so:

Thread printThread = new Thread(printWorker);

printThread.Name = "Logger MainThread";
printThread.IsBackground = true;
printThread.Start();

When my main thread finishes, this new thread just keeps on working, although it's marked as Background.

What could be the causes for this? This object is holding a Mutex object, not sure this may be the reason...

Any ideas anyone?

Here's the code from the printWorker method:

while (loggerIsActive)
{
    LogMessage log = LoggerQueue.Dequeue();

    if (log.message != null)
    {
        syncLogObj.WaitOne();
        lock (writerobj)
        {
            StreamWriter sw;

            if (!File.Exists(fName))
            {
                sw = File.CreateText(fName);
            }
            else
            {
                sw = new StreamWriter(fName, true);
            }

            using (sw)
            {
                if (log.message != "")
                {
                    if (log.message.EndsWith("\r\n"))
                    {
                        log.message =
                            log.message.Substring(0, log.message.Length - 2);
                    }

                    sw.WriteLine(string.Format("[{0}][{3}][{1}] | {2}",
                                               log.msgTime,
                                               log.level.ToString(),
                                               log.message,
                                               log.sender.ToString()));
                }

                sw.Flush();
                sw.Close();
            }
        }

        syncLogObj.ReleaseMutex();
    }

    Thread.Sleep(5);
}
like image 925
lysergic-acid Avatar asked May 24 '11 11:05

lysergic-acid


People also ask

How do you end a thread when the main program ends?

If you make your worker threads daemon threads, they will die when all your non-daemon threads (e.g. the main thread) have exited. Thanks for the simple and precise answer, the default threading. Thread daemon status isDaemon() is False, set it True by setDaemon(True) . This answers the question and just works.

Why is it important for the main thread to terminate at the end?

There are certain properties associated with the main thread which are as follows: It is the thread from which other “child” threads will be spawned. Often, it must be the last thread to finish execution because it performs various shutdown actions.

Do threads terminate automatically?

A thread automatically terminates when it returns from its entry-point routine. A thread can also explicitly terminate itself or terminate any other thread in the process, using a mechanism called cancelation.

What happens when a thread finishes?

Finishing Threads So when does a thread finish? It happens in one of two cases: all instructions in the Runnable are executed. an uncaught exception is thrown from the run method.


2 Answers

kill it.

Not pretty. But this isn't TV. Read on:

1) Not sure you use are using it but it appears you should be locking loggerqueue before you queue(main pgm) or dequeue(thread).
2) No need to lock writerobj with just this setting. But really you should so you can safely kill the thread not during a write:

  • main thread:
    • do everything
    • before close: -lock writerobj -printthread.abort
  • worker thread:
    • add try catch to handle threadabort exception and just quit

If you're properly doing this, you shouldn't have to use Waits and mutexes. If you are using wait properly anyway you won't need the sleep.

General advice for this application: why not log on main thread? if your logging is that busy, log results will be pretty useless.

But there are rare cases where that might be wrong. Entonces......

General advice to have threads play nice for this problem:

  • Main program
    • encapsulate logging (notably, quit flag, queue, and worker thread ref) in an object
    • 'global snobs?' Logging is a rare excuse to use singleton patter.
    • start worker thread in logger object via method
    • main thread always calls a single method on logger object to log error
    • That method locks the queue and adds to it.
    • Use Monitor/Pulse/Wait, no sleep; full examples abound; it is worth learning
      • because only this thread is hitting the file anyway, unless you have multiple processes, you don't need waitone/releasemutex.
    • That logging method monitor.pulses an object
    • That frees the worker thread's monitor.wait (which is what idles the CPU instead of sleep)
    • lock the queue, only inside the lock dequeue the object to local ref; nothing else.
    • Do your normal logging code and 'exit check' loop. Add
      • Your logic code could leave message unwritten if queue is full on quit:
      • change to exit check so you can do it without an extra lock of queue:
        • move declaration of queued object refernce above while; set it to nothing
        • change logic in while to 'loggerisactive or log != null'
    • when your main thread finishes, in your exit code:
      • set the quit flag
      • pulse the object you're using to wait incase it's not processing the queue
      • Thread will fall thru.
like image 71
FastAl Avatar answered Oct 24 '22 08:10

FastAl


Try this:

Start the app through VS and exit normally. The VS should stay in Debug mode as you described. Click on Pause button (Break all) and then go to Debug->Windows->Threads. Do you see your "Logger MainThread" in the list?

  • If so, double-click it, it should lead you to the code line that the thread is currently executing. Step-debug from there and see why is it not terminating.
  • If you don't see it try looking at other threads that have not terminated and try to find the problem.

Otherwise, with those kind of problems it's always useful to monitor the program state via System.Diagnostics.Debug.Print statements (you can see them printing in the VS output window).

like image 38
Boris B. Avatar answered Oct 24 '22 08:10

Boris B.