【问题标题】:signaling a sleeping thread发出休眠线程的信号
【发布时间】:2010-08-14 23:19:43
【问题描述】:

我是 c# 中的多线程新手,对所有线程的东西感到困惑。 这是我想要的:

public class TheClass
{
    Thread _thread;
    bool _isQuitting;
    bool _isFinished;
    object jobData;
    public void Start()
    {
        jobData = new object();
        _thread = new Thread(new ThreadStart(Run));
        _thread.Start();
    }
    private void Run()
    {
        while (!_isQuitting)
        {
            lock (jobData) // or should i use mutex or monitor?
            {
                DoStuff();
            }
            // sleep till get triggered
        }
        DoCleanupStuff();
        _isFinished = true;
    }

    public void AddJob(object param)
    {
        jobData = param;
        //wake up the thread
    }
    public void Stop()
    {
        _isQuitting = true;
        //wake up & kill the thread
        //wait until _isFinished is true
        //dispose the _thread object
    }
}

在这个类中,实现注释掉的短语和整体性能的最有效方法是什么?

【问题讨论】:

  • 只是几个cmets: ①你的jobData对象最初是空的,所以如果用户在调用AddJob之前调用Run,它就会崩溃。要解决此问题,您可以将 object jobdata; 更改为 object jobdata = new object();。 ②Run方法好像根本没有用到它的参数,所以你可以直接去掉它,用ThreadStart代替ParameterizedThreadStart

标签: c# multithreading events triggers


【解决方案1】:

考虑使用Monitor.Wait()Monitor.Pulse()

例如:

object locker = new object();

private void Run()
{
    while (!_isQuitting)
    {
        lock (locker)
        {
            Monitor.Wait(locker);
            DoStuff(jobData);
        }
    }
    DoCleanupStuff();
}

public void AddJob(object param)
{
    // Obtain the lock first so that you don’t
    // change jobData while the thread is processing it
    lock (locker)
    {
        jobData = param;
        Monitor.Pulse(locker);
    }
}

public void Stop()
{
    lock (locker)
    {
        _isQuitting = true;
        Monitor.Pulse(locker);
    }

    // Wait for the thread to finish — no need for _isFinished
    _thread.Join();
}

但是,请注意,在我的代码中,您仍然只有一个 jobData 对象 — 结果是 AddJob() 将等待当前作业完成处理。这可能不是你想要的。也许你应该有一个Queue<T> 的工作数据对象; AddJobEnqueue 一个项目,Run 将保持 Dequeue'ing 直到队列为空。如果这样做,Run 中的 lock 语句应该只包含对队列的访问,而不是整个处理阶段。

【讨论】:

    【解决方案2】:

    我不知道性能如何,但看起来你想要AutoResetEvent

    这无疑为您提供了一种最简单的方法来执行您所描述的操作。测试一下,如果你发现性能是个问题,那就考虑另一种方法。

    【讨论】:

      【解决方案3】:

      在我看来,您想使用生产者/消费者模式。使用阻塞队列最容易做到这一点。一旦你有了它,那么其他一切都很容易。你可以找到一个实现 here 或者你可以使用 4.0 中的 BlockingCollection 类。

      注意:为简洁起见,省略了强化代码。

      public class TheClass
      {
          private Thread m_Thread;
          private BlockingCollection<object> m_Queue = new BlockingCollection<object>();
          private CancellationTokenSource m_Cancellation = new CancellationTokenSource();
      
          public void Start()
          {
              m_Thread = new Thread(new ThreadStart(Run));
              m_Thread.IsBackground = true;
              m_Thread.Start();
          }
      
          private void Run()
          {
              while (true)
              {
                  try
                  {
                      object job = m_Queue.Take(m_Cancellation.Token);
                  }
                  catch (OperationCanceledException)
                  {
                      break;
                  }
              }
          }
      
          public void AddJob(object param)
          {
              m_Queue.Add(param);
          }
      
          public void Stop()
          {
              m_Cancellation.Cancel();
              m_Thread.Join();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-08
        • 2018-01-15
        • 1970-01-01
        • 2011-09-18
        • 1970-01-01
        • 2014-06-01
        相关资源
        最近更新 更多