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

时间:2011-05-24 11:13:00

标签: c# multithreading

我有一个奇怪的问题:

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

Thread printThread = new Thread(printWorker);

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

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

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

6 个答案:

答案 0 :(得分:12)

试试这个:

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

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

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

答案 1 :(得分:7)

杀了它。

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

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

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

如果您正确执行此操作,则不必使用Waits和互斥锁。无论如何,如果你正在使用等待,你将不需要睡眠。

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

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

使线程能够很好地解决这个问题的一般建议:

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

答案 2 :(得分:4)

你有很多事情发生,你显然没有表现出来......

例如:您有syncLogObj.WaitOne();,但我们没有看到宣布syncLogObj的位置,或者在您的计划中的其他位置使用过。

另外,你不需要它......完全摆脱syncLogObj的东西(包括“ReleaseMutex”垃圾)......你已经有了一个锁(blah){},这就是全部你需要(从你显示的代码)。

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

所以,简单的说明

  1. 摆脱syncLogObj(因为你已经拥有“锁定”)
  2. 确保在某处设置loggerIsActive = false
  3. 编辑:更多细节!

    从我看到的内容 - 您根本不需要lock (writerobj),因为(我很确定),您似乎只有一个帖子即写入日志。

    只有当你有两个或更多个线程运行该代码时(基本上)才会出现“锁定”。

答案 3 :(得分:3)

如果在你的主线程完成之前printworker没有完成,那么main将会死掉,你的printworker线程将被操作系统杀死。如果您希望main等待您创建的主题,那么您应该在main中调用printThread.Join()。那将是主要的等待你的线程。

当主程序完成后你的程序会死掉,你的printThread将被操作系统销毁,它将无法继续运行。

来自here

  

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

答案 4 :(得分:2)

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

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

答案 5 :(得分:1)

Thread.Abort();
Thread.Dispose();

如果我没弄错的话应该这样做。