2012-02-08 68 views
2

我想如何在線程之間傳輸鎖?

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上。怎麼做?我應該使用線程間通信嗎?

+8

你可能做錯了什麼。這是什麼用例? – 2012-02-08 21:37:40

+0

爲什麼不把'Monitor.Enter'放在工作項目內? – Yahia 2012-02-08 21:39:37

+3

是否有你無法鎖定queueUserWorkItem委託內的對象的原因? (您可以鎖定然後解鎖項目,以便/ *做某些事情* /如果需要排隊該項目之前發生的事情。) – Servy 2012-02-08 21:40:09

回答

5

Semaphore s允許您將它們鎖定在一個線程中並在另一個線程中解鎖它們。

但是這種行爲對我來說是非常可疑的......你究竟在做什麼?這在實踐中幾乎不應該做。

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; 
    } 
} 
+0

我想過使用'SemaphoreSlim',但它是專爲短暫的等待期 – 2012-02-09 12:06:52

5

您可以爲此使用Mutexes。它們就像鎖,但具有更多的功能。他們也更昂貴。

正如你一定已經知道,你在這裏是危險的領土。跨線程傳遞鎖定是危險的...

13

如何在線程之間轉移鎖嗎?

你在初始線程上輸入顯示器,比如線程Alpha。嘗試進入顯示器的任何其他線程都會阻塞,直到顯示器可用。

然後,如果您想鎖轉移到另一個線程,說線程布拉沃,同時仍然能夠恢復線程阿爾法與顯示器時布拉沃做的所有權,然後你把阿爾法在等待狀態在顯示器上。如果線程布拉沃是阻止在監視器上然後醒來,進入監視器。當它完成時,它會丟棄顯示器,它放棄了Bravo對顯示器的所有權,並將所有權轉移回Alpha,後者醒來並繼續以顯示器的所有權運行。 (1)你不應該試圖在第一時間做到這一點;但是,如果你完全不清楚這一點,

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

0

如果埃裏克Lipert的回答適合我,我會實現:如果你弄錯了,和(2)你應該閱讀這是超級危險的

lock(this.StaticLock) 
{ 
    ThreadPool.QueueUserWorkItem(state => 
    { 
     lock(this.StaticLock) 
     { 
      // Do something ... 

      Monitor.Pulse(this.StaticLock); 
      // Do something else... 

     } 
    }); 
    Monitor.Wait(this.StaticLock); 
} 

不幸的是這個解決方案沒有按」防止另一個線程鎖定this.StaticLock Monitor.Wait和隊列之間的線程鎖

1

一種替代方法是使用WaitHandle

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

     } 
     finally 
     { 
      waitHandle.Set(); 
     } 

     // Do something else... 

    } 
} 

waitHandle.WaitOne();