c# – 报告线程进度的最佳方式

前端之家收集整理的这篇文章主要介绍了c# – 报告线程进度的最佳方式前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个程序,它使用线程顺序执行耗时的进程.我希望能够监视每个线程的进度,类似于BackgroundWorker.ReportProgress / ProgressChanged模型的工作方式.由于我所处的其他限制,我无法使用ThreadPool或BackgroundWorker.允许/公开此功能的最佳方法是什么.重载Thread类并添加属性/事件?另一个更优雅的解决方案?

解决方法

Overload the Thread class and add a
property/event?

如果通过“超载”你实际上意味着继承然后没有.线程被密封,因此无法继承,这意味着您将无法向其添加任何属性或事件.

Another more-elegant solution?

创建一个封装将由线程执行的逻辑的类.添加可用于从中获取进度信息的属性或事件(或两者).

public class Worker
{
  private Thread m_Thread = new Thread(Run);

  public event EventHandler<ProgressEventArgs> Progress;

  public void Start()
  {
    m_Thread.Start();
  }

  private void Run()
  {
    while (true)
    {
      // Do some work.

      OnProgress(new ProgressEventArgs(...));

      // Do some work.
    }
  }

  private void OnProgress(ProgressEventArgs args)
  {

    // Get a copy of the multicast delegate so that we can do the
    // null check and invocation safely. This works because delegates are
    // immutable. Remember to create a memory barrier so that a fresh read
    // of the delegate occurs everytime. This is done via a simple lock below.
    EventHandler<ProgressEventArgs> local;
    lock (this)
    {
      var local = Progress;
    }
    if (local != null)
    {
      local(this,args);
    }
  }
}

更新:

让我更清楚一下为什么在这种情况下需要记忆障碍.屏障可防止在其他指令之前移动读取.最可能的优化不是来自cpu,而是来自JIT编译器“提升”while循环之外的Progress的读取.这种运动给人的印象是“陈旧”的阅读.这是一个问题的半现实演示.

class Program
{
    static event EventHandler Progress;

    static void Main(string[] args)
    {
        var thread = new Thread(
            () =>
            {
                var local = GetEvent();
                while (local == null)
                {
                    local = GetEvent();
                }
            });
        thread.Start();
        Thread.Sleep(1000);
        Progress += (s,a) => { Console.WriteLine("Progress"); };
        thread.Join();
        Console.WriteLine("Stopped");
        Console.ReadLine();
    }

    static EventHandler GetEvent()
    {
        //Thread.MemoryBarrier();
        var local = Progress;
        return local;
    }
}

必须在没有vshost进程的情况下运行Release构建.任何一个都将禁用显示错误的优化(我相信这在框架版本1.0和1.1中也不可重现,因为它们更原始的优化).错误是“Stopped”永远不会显示,即使它显然应该是.现在,取消对Thread.MemoryBarrier的调用,并注意行为的变化.还要记住,即使对此代码结构进行的最微妙的更改,也会阻止编译器进行优化的能力.一个这样的改变是实际调用委托.换句话说,您目前无法使用空检查后跟调用模式重现陈旧的读取问题,但CLI规范(我知道无论如何)中没有任何内容禁止未来假设的JIT编译器重新应用“提升”优化.

猜你在找的C#相关文章