【问题标题】:How to transfer locks between threads?如何在线程之间传递锁?
【发布时间】:2012-02-08 21:36:29
【问题描述】:

我愿意

Monitor.Enter(this.StaticLock);
try
{
    // Do something ...

    ThreadPool.QueueUserWorkItem(state =>
    {
        try
        {
             // Do something else...

        }
        finally
        {
            Monitor.Exit(this.StaticLock);
        }
    });
}
catch (Exception)
{
    Monitor.Exit(this.StaticLock);
    throw;
}

但它不起作用,因为它不能 Monitor.Exit 在当前线程中不是 Monitor.Enter 的对象上。怎么做?我应该使用线程间通信吗?

【问题讨论】:

  • 你可能做错了什么。这有什么用例?
  • 为什么不把Monitor.Enter放在工作项里面?
  • 有什么原因不能锁定 queueUserWorkItem 委托中的对象? (如果需要,您可以锁定然后解锁该项目,以便在排队项目之前发生 /*做某事*/。)
  • 下面的catch块只会在ThreadPool.QueueUserWorkItem引发异常时引发,而不是里面的代码......
  • catch 块只会在 QueueUserWorkItem 引发异常时引发,你有一个设计问题,你应该按照@yahia 所说的那样锁定工作项,

标签: c# .net multithreading concurrency locking


【解决方案1】:

如何在线程之间传递锁?

您在初始线程上进入监视器,例如线程 Alpha。任何其他试图进入监视器的线程都会阻塞,直到监视器可用。

如果你想将锁转移到另一个线程,比如线程 Bravo,同时在 Bravo 完成后仍然能够恢复线程 Alpha拥有监视器的所有权,那么你将 Alpha 放在等待在显示器上的状态。如果线程 Bravo 在监视器上被阻塞,则它会唤醒并进入监视器。完成后,它脉冲监视器,放弃 Bravo 对监视器的所有权并将所有权转回给 Alpha,Alpha 唤醒并继续以监视器的所有权运行。

如果您对此完全不清楚,那么 (1) 您一开始就不应该尝试这样做;如果你弄错了,这是非常危险的,并且(2)你应该阅读这个:

http://www.codeproject.com/Articles/28785/Thread-synchronization-Wait-and-Pulse-demystified

【讨论】:

    【解决方案2】:

    Semaphores 允许您将它们锁定在一个线程中并在另一个线程中解锁它们。

    但是这种行为对我来说非常可疑......你到底想完成什么?在实践中几乎不应该这样做。

    static readonly Semaphore semaphore = new Semaphore(1, 1);
    
    void Method1()
    {
        semaphore.WaitOne();
        try
        {
            // Do something ...
    
            new Thread(() =>
            {
                try
                {
                    // Do something else...
    
                }
                finally
                {
                    semaphore.Release();
                }
            }).Start();
        }
        catch (Exception)
        {
            semaphore.Release();
            throw;
        }
    }
    

    【讨论】:

    • 我曾想过使用SemaphoreSlim,但它是为短等待时间设计的
    【解决方案3】:

    您可以为此使用互斥锁。它们就像锁,但具有更多功能。它们也更贵。

    您肯定已经知道,您在这里处于危险的境地。跨线程传递锁是危险的......

    【讨论】:

      【解决方案4】:

      另一种方法是使用 WaitHandle

      var waitHandle = new AutoResetEvent(initialState: false);
      ThreadPool.QueueUserWorkItem(state =>
      {
          lock(this.staticLock)
          {
              try
              {
                  // Do something ...
      
              }
              finally
              {
                  waitHandle.Set();
              }
      
              // Do something else...
      
          }
      }
      
      waitHandle.WaitOne();
      

      【讨论】:

        【解决方案5】:

        如果 Eric Lippert 的回答适合我,我会实施:

        lock(this.StaticLock)
        {
            ThreadPool.QueueUserWorkItem(state =>
            {
                lock(this.StaticLock)
                {
                     // Do something ...
        
                     Monitor.Pulse(this.StaticLock);
                     // Do something else...
        
                }
            });
            Monitor.Wait(this.StaticLock);
        }
        

        不幸的是,这个解决方案并不能阻止另一个线程在 Monitor.Wait 和排队线程锁之间锁定 this.StaticLock

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-01-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-30
          • 1970-01-01
          相关资源
          最近更新 更多