线程不';t在主线程结束时终止

本文关键字:线程 结束 终止 | 更新日期: 2023-09-27 17:57:26

我有一个奇怪的问题:

在我的C#应用程序中,我正在创建另一个线程,就像这样:

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

当我的主线程完成时,这个新线程继续工作,尽管它被标记为Background。

造成这种情况的原因是什么?此对象持有一个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);
}

线程不';t在主线程结束时终止

试试这个:

通过VS启动应用程序并正常退出。VS应保持在调试模式,如您所述。单击暂停按钮(全部中断),然后转到调试->窗口->线程。您在列表中看到您的"Logger MainThread"了吗?

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

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

杀死它

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

1) 不确定您是否正在使用它,但似乎应该在排队(主pgm)或出列(线程)之前锁定loggerqueue
2) 无需仅通过此设置锁定writerobj。但实际上你应该这样做,这样你就可以安全地杀死线程,而不是在写:

  • 主螺纹:
    • 什么都做
    • 关闭前:-锁定写robj-打印螺纹。bort
  • 工作线程:
    • 添加try-catch来处理threadabort异常并立即退出

如果您正确地做到了这一点,就不应该使用Wait和互斥。如果你正确使用wait,你就不需要睡眠了。

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

但在极少数情况下,这可能是错误的。Enonces。。。。。。

让线程处理这个问题的一般建议:

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

你有很多事情显然没有表现出来。。。

Exmaple:您有syncLogObj.WaitOne();,但我们看不到syncLogObj在哪里被声明,也看不到在程序的其他地方被使用。

另外,你不需要它…完全去掉syncLogObj的东西(包括"ReleaseMutex"垃圾)。。。您已经有了一个锁(blah){},这就是您所需要的(根据您显示的代码)。

主线程很可能没有结束,可能是因为这个或其他对象使它保持打开状态。

所以,简单的说明

  1. 去掉syncLogObj(因为你已经有了"锁")
  2. 确保将loggerIsActive = false设置在某个位置

编辑:更多细节

据我所见-您根本不需要lock (writerobj),因为(我很确定),您似乎只有一个线程在写入日志。

只有当您有两个或多个线程运行该代码(基本上)时,"锁"才存在。

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

当main完成时,您的程序将失效,并且您的printThread将被操作系统销毁,它将无法继续运行。

从这里

背景线程与前台线程,但有一个例外:后台线程不保留托管执行环境正在运行。一旦所有前台线程在托管进程中停止(其中.exe文件是托管程序集),系统停止所有后台线程并关闭。

Tony the Tiger有正确的想法,但需要添加额外的代码来在应用程序关闭之前杀死线程。

printThread.Join(1000);
if(printThread!=null && printThread.IsAlive)
    printThread.Abort();
Thread.Abort();
Thread.Dispose();

如果我没记错的话,那就行了。