【问题标题】:Is there a way to get a notification, when the main thread stops in C#当主线程在 C# 中停止时,有没有办法获得通知
【发布时间】:2014-07-17 12:23:30
【问题描述】:

我正在编写一个使用单独线程进行日志记录的应用程序。 当主线程停止时,我想停止单独的线程。但是我无法弄清楚何时停止记录器线程,因为我不知道主线程何时停止。 C# 中是否有一种机制可以在主线程停止时发送通知? (或者你能想出另一种解决我问题的方法吗?)

// This class automatically applies on each call of every method of Main() function
public class CommandLoggingAdvice : IMethodInterceptor
{
    private static ProducerConsumerClass LoggingQueue = ProducerConsumerClass.Instance;    
                LoggingQueue.AddTask("Logging message on call of *method*");            
}

public sealed class ProducerConsumerClass
{
    // here Iget an instance of log4net
    private ILog _Logger = null;
    protected ILog Logger
    {
        _Logger = LogManager.GetLogger("Logger1");            
    }

    private BlockingCollection<string> tasks = new BlockingCollection<string>();

    private static volatile ProducerConsumerClass _instance;     
    Thread worker;
    private Thread mainthread;

    private ProducerConsumerClass()
    {
        mainthread = Thread.CurrentThread;
        worker = new Thread(Work);
        worker.Name = "Queue thread";
        worker.IsBackground = false;
        worker.Start(mainthread);
    }

    public static ProducerConsumerClass Instance
    {
       get
       {
            if (_instance == null)       
            {
                _instance = new ProducerConsumerClass();
            }
       }
    }

    public void AddTask(string task)
    {
        tasks.Add(task);           
    }


    void Work(object mainthread)
    {
        Thread ma = (Thread) mainthread;
        if(ma.ThreadState != ThreadState.Stopped)
        {
             tasks.CompleteAdding();
        }
        while (true)
        {
            string task = null;
            if (!tasks.IsCompleted)
            {
                task = tasks.Take();
                Logger1.Info(task);   
            }
            else
            {
                return;
            }              
        }
    }
}

如果 BlockingCollection 为空且应用程序仍在工作,则循环再调用一次 Take(),结果:记录器线程现在已暂停。所以当 main thread.Threadstate == Stopped 时,我需要杀死 logger 线程

在 cmets 中添加了有关问题的更多信息

【问题讨论】:

  • “你的”线程是主线程运行的同一个应用程序的一部分吗?
  • 对,没错,而且IsBackground = false
  • 你的主线程究竟是如何终止的?
  • 像往常一样...所有工作都完成了,我调用 return 0;
  • 请添加显示您如何启动后台线程的代码。这个问题听起来也很像stackoverflow.com/questions/1368697/…

标签: c# multithreading spring-aop spring.net thread-synchronization


【解决方案1】:

如果BlockingCollection 为空并标记为已完成,则线程中已有代码退出。您的循环检查 IsCompleted 并退出。

您需要某种方式让主线程在集合上调用CompleteAdding。我会在您的ProducerConsumerClass 中推荐一个公共方法:

public void AllDone()
{
    tasks.CompleteAdding();
}

所以主线程在完成处理后可以调用AllDone。然后您的线程将清空队列并退出。

顺便说一句,编写日志循环的更简洁的方法是:

foreach (string task in tasks.GetConsumingEnumerable())
{
    Logger1.Info(task);
}

这也使得将来添加取消支持变得更加容易。

【讨论】:

  • 感谢您的回答!这是我心目中的第一个解决方案,但存在封装问题:所有使用 blockingCollection 的工作都集中在一个地方:CommandLoggingAdvice 类;并且如果有一个开发人员只将日志类添加到一个或其他程序(如果他是日志专家并且他的唯一职责是编写日志类),这会给他带来问题:他将不得不更改程序代码程序,所以不会有独立的日志记录类...
  • 关于“foreach”构造 - 我不确定在“获取”队列中的最后一个元素之后,是否还会再获取一次,这会导致日志线程暂停(因此线程不会使用 CPU时间”
  • 关于 CancellationToken... 这将帮助我解决问题,但我仍然无法抓住时机、地点和方式,如何使用它:因为日志记录线程已暂停,我我无法从中调用 Token 方法,主线程即将终止,我不知道如何从单例类中捕获任何终止事件; CommonLoggingClass 是 Spring.AOP 框架的实现:它只等待 Main() 函数调用函数 - 所以 CommonLoggingClass 不知道主线程何时终止。
  • 我尝试设置 Logging 线程属性 IsBackground = true 并使用 Singleton Dispose/Finalize 方法,在这种情况下,在主线程终止后立即自动调用这些方法......并且 Dispose { tasks.Completeadding ; worker.Join;} - 有一个想法是我可以强制主线程等待后台日志记录线程......但这不起作用
  • 所以现在我有两个所谓的“不好的解决方案”来解决我的问题:1)我在 Work(object mainthread) 方法中创建了新的并行线程,它一直等到主线程终止:mainthread.Join( ) 并调用 Tasks.IsCompleted() 和 tasks.Dispose() 2) 我不会暂停日志线程直到事件发生:我现在使用 TryTake 和 TryAdd,以及 loggingthread.sleep(250) - 我在十分之一秒后暂停线程然后它唤醒并检查是否应该终止
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-12
  • 2020-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多