主线程完成后,线程不会终止

lys*_*cid 12 c# multithreading

我有一个奇怪的问题:

在我的C#app中,我正在创建另一个线程,如下所示:

Thread printThread = new Thread(printWorker);

printThread.Name = "Logger MainThread";
printThread.IsBackground = true;
printThread.Start();
Run Code Online (Sandbox Code Playgroud)

当我的主线程完成时,这个新线程继续工作,虽然它被标记为背景.

可能是什么原因造成的?这个对象持有Mutex对象,不确定这可能是原因......

任何人的想法?

这是printWorker方法的代码:

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);
}
Run Code Online (Sandbox Code Playgroud)

Bor*_* B. 12

试试这个:

通过VS启动应用程序并正常退出.如您所述,VS应保持在调试模式.单击Pause按钮(全部中断),然后转到Debug-> Windows-> Threads.你在列表中看到了"Logger MainThread"吗?

  • 如果是这样,双击它,它将引导您到线程当前正在执行的代码行.从那里进行步骤调试,看看它为什么不终止.
  • 如果你没有看到它尝试查看尚未终止的其他线程并尝试找到问题.

否则,对于这些问题,通过System.Diagnostics.Debug.Print语句监视程序状态总是有用的(您可以在VS输出窗口中看到它们打印).

  • 您应该已经提到了记录器线程在另一个AppDomain中运行的小细节:).另一个AppDomain是另一个孤立的exec.关闭应用程序不会杀死来自其他appdomain的线程,我不会感到惊讶.事实上,如果是这样的话,我会感到惊讶,因为那时它不会是一个孤立的执行环境.现在我明白为什么你需要一个完全成熟的Mutex对象而不是简单的锁...... (10认同)
  • 这只是一个建议,由于缺乏任何其他解释,我想到了这个解释.我没有写这个代码,我不知道在哪些上下文创建它.现在我们提出了这个选项,它符合要求 - 如果另一个AppDomain中的某些代码正在创建此对象并生成新线程,则在卸载主AppDomain时该线程不会退出.将在明天@办公室验证这一点.如果是这种情况,我需要提出一个解决方案,以便在应用程序关闭时销毁此应用程序域. (2认同)

Fas*_*tAl 7

杀死它.

不漂亮.但这不是电视.继续阅读:

1)不确定您是否正在使用它,但看起来您应该在排队(主pgm)或出队(线程)之前锁定loggerqueue.
2)无需仅使用此设置锁定writerobj.但实际上你应该如此安全地在写入期间杀死线程:

  • 主线程:
    • 做任何事
    • 在关闭之前:-lock writerobj -printthread.abort
  • 工作线程:
    • 添加try catch来处理threadabort异常,然后退出

如果你正确地这样做,你不应该使用Waits和互斥量.无论如何,如果你正在使用等待,你将不需要睡眠.

对此应用程序的一般建议:为什么不登录主线程?如果您的日志记录繁忙,则日志结果将毫无用处.

但是在极少数情况下这可能是错误的.Entonces ......

有线程的一般建议可以解决这个问题:

  • 主程序
    • 在对象中封装日志记录(特别是退出标志,队列和工作线程引用)
    • '全球势利小人?' 记录是使用单例模式的罕见借口.
    • 通过方法在logger对象中启动工作线程
    • 主线程总是在logger对象上调用单个方法来记录错误
    • 该方法锁定队列并添加到队列中.
    • 使用监视/脉冲/等待,不睡觉; 完整的例子比比皆是; 这是值得学习
      • 因为只有这个线程无论如何都要击中文件,除非你有多个进程,否则你不需要waitone/releasemutex.
    • 那个日志记录方法监视一个对象
    • 这释放了工作线程的monitor.wait(这是CPU闲置而不是睡眠)
    • 锁定队列,只在锁内将对象出列到本地ref; 没有其他的.
    • 执行正常的日志记录代码和"退出检查"循环.加
      • 如果退出队列已满,您的逻辑代码可能会使消息不成文:
      • 更改为退出检查,以便您可以在没有额外的队列锁的情况下执行此操作:
        • 移动上面排队对象引用的声明; 把它设置为空
        • 将逻辑更改为'loggerisactive或log!= null'
    • 主线程完成后,在退出代码中:
      • 设置退出标志
      • 脉冲您正在使用的对象等待它不处理队列
      • 线程将通过.


Ton*_*ion 3

如果printworker在主线程完成之前没有完成,那么 main 将终止,并且您的printworker线程将被操作系统杀死。如果你想让main等待你创建的线程,那么你应该printThread.Join()在main中调用。这将使 main 等待你的线程。

当 main 完成时,您的程序死亡并且您的程序printThread将被操作系统销毁,它将不会继续运行。

这里

后台线程与前台线程相同,但有一个例外:后台线程不会使托管执行环境保持运行。一旦托管进程(其中 .exe 文件是托管程序集)中的所有前台线程都已停止,系统就会停止所有后台线程并关闭。