0

我正在開發一個C#4.5應用程序,其中許多線程將需要訪問相同的串行端口。C#Monitor.Enter SynchronizationLockException

因爲我也會在串口上接收響應,所以我想避免進一步寫入,直到我收到響應並讀取它。

我有一個SerialHandler類是SerialPort類的包裝,寫入和讀取方法看起來是這樣的:

public void write(string message) 
{ 
    Monitor.Enter(lockingObject); 
    //Stuff 
    serialPort.write(message); 
} 

public string read() 
{ 
    //Reading procedure 
    Monitor.Exit(lockingObject); 
} 

但只要我發出了從形式寫我得到的SynchronizationLockException說「對象同步方法是從一個非同步的代碼塊調用的」。 lockingObject是一個私有的只讀對象變量。

我該如何避免此錯誤? 非常感謝

編輯,就應該像這樣工作:
線程A獲得訪問讀/寫
線程B試圖訪問,但未能
線程A獲得讀那麼他釋放了鎖
線程B現在可以執行寫操作,得到他的鎖,讀取和刪除他鎖

+0

爲什麼使用顯示器,而不是直接的鎖? – willaien

+0

因爲我需要在一個方法中鎖定訪問並在另一個方法中釋放它 –

+1

這個異常說你在調用write()之前調用了read()*。這是一個錯誤。 –

回答

0

拋出異常,因爲不同的線程是trying to release the object

這是一個簡單的解決問題的方法:

class MySerialPort 
{ 
    private AutoResetEvent _waithandle = new AutoResetEvent(true); 
    private SerialPort _serialPort; 

    public void write(string message) 
    { 
     _waithandle.WaitOne(); 
     //Stuff 
     _serialPort.Write(message); 
    } 

    public string read() 
    { 
     try 
     { 
      ... 
      ... 
     } 
     finally 
     { 
      _waithandle.Set(); 
     } 
    } 

} 

第一個線程會寫,那麼任何新的寫操作將被阻塞,直到讀會釋放其中一人。

編輯

我在下面,你正在尋找最快的解決方案的評論看到。 acording對這一link,下面的代碼會做在60ns的工作(英特爾酷睿i7 860),這是更好的

class MySerialPort 
{ 
    private ManualResetEventSlim _waithandle = new ManualResetEventSlim(true); 
    private SerialPort _serialPort; 
    private readonly object _sync = new object(); 

    public void write(string message) 
    { 
     lock (_sync) 
     { 
      _waithandle.Wait(); 
      //Stuff 
      _serialPort.Write(message); 
      _waithandle.Reset(); 
     } 

    } 

    public string read() 
    { 
     try 
     { 
     .... 
     } 
     finally 
     { 
      _waithandle.Set(); 
     } 
    } 
} 
+0

我有一個問題,如果waitCounter是0,WaitOne會被調用。這是否意味着發生?它不會等待什麼,因爲沒有人會打電話給Set? –

+0

'Interlocked.Increment'增加後返回數值,所以你不會阻塞第一個線程.... –

+0

哦,我明白了,非常感謝!所以它會一直等待,除非值爲0 –

-2

你可以使用互斥

class SerialHandler 
{ 
    private Mutex _mutex = new Mutex(); 
    private SerialPort _serialPort; 
    public void write(string message) 
    { 
     _mutex.WaitOne(); 
     //Stuff 
     _serialPort.write(message); 
    } 

    public string read() 
    { 
     //Reading procedure 
     _mutex.ReleaseMutex(); 
    } 
} 

問題MEA你已經嘗試釋放未獲取的鎖。

+1

哦,我想他們會,他們不工作就像「鎖」關鍵字?我從來沒有鎖過這些問題。這是我第一次使用Monitor tho,而且我對多線程相對來說比較陌生,無論如何感謝您的回答! –

+0

'lock'必須被一個同步的代碼塊使用,所以它被按照定義由同一個線程使用。在這種情況下,Monitor.Enter和Monitor.Exit被調用,但它們總是在同一個線程中調用。 –

+0

嗯,我需要它被調用相同的線程:類似於: 線程A獲取讀取/寫入 線程B試圖獲得訪問,但失敗 線程A獲取閱讀,所以他釋放他的鎖 線程B現在可以執行寫入,取得鎖定,讀取並解除鎖定 –

相關問題