C#多線程問題(從不同步的代碼塊中調用了對象同步方法。)
代碼如下:
private void button4_Click(object sender, EventArgs e)
{
Thread t1 = new Thread(new ThreadStart(a));
t1.Start();
}
public void a()
{
Monitor.TryEnter(this, 5000);
//
///程序代碼,執行正常
//
for (int i = 0; i < 4; i++)
{
Thread.Sleep(800);
}
Monitor.Exit(this);
}
執行上面程序,如果只通過點擊1,2次,或是隔一段時間才點擊,那程序是沒有問題的。但若是連續快速點擊,Monitor.Exit(this);就會提示“從不同步的代碼塊中調用了對象同步方法。”這個異常,把5000調到10000情況會有所改善。但這樣太慢了,我是要把這段東西放在timer里面的。請問高手為什么會引發這個問題?怎樣解決?
解決方案 »
-
1)嘗試用lock
2)推薦用Autoeventset -
用過lock,問題更嚴重,基本上每點擊都出錯。Autoeventset能詳細說明一下嗎? -
使用 Monitor 鎖定對象(即引用類型)而不是值類型。將值類型變量傳遞給 Enter 時,它被裝箱為對象。如果再次將相同的變量傳遞給 Enter,則它被裝箱為一個單獨對象,而且線程不會阻止。Monitor 本應保護的代碼未受保護。此外,將變量傳遞給 Exit 時,也創建了另一個單獨對象。因為傳遞給 Exit 的對象和傳遞給 Enter 的對象不同,Monitor 將引發 SynchronizationLockException
-
這個可能是你用TRYENTER的原因,這個東西不能確保你得到排他鎖,所以你在這里要進行異常判斷。MSDN也是這樣要求的。我估計可能是在沒有EXIT時你去獲取了鎖而沒有成功,緊接着馬上EXIT,於是又一個線程進入。形成兩個線程競爭。
-
我估計你增加一個判斷,如果沒有得到便RETURN結束新生成的線程。可能會變好。
-
private void button1_Click(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(a), null);
}
public void a( object oo)
{
///程序代碼,執行正常
//
for (int i = 0; i < 4; i++)
{
Thread.Sleep(800);
}
} -
我做了測試,沒問題了。呵呵。原理是按樓上所說,但分析可能是我所想。看樣子還是那句話,多看MSDN
-
1)我用lock 沒有發現問題
lock 確保當一個線程位於代碼的臨界區時,另一個線程不進入臨界區。如果其他線程試圖進入鎖定的代碼,則它將一直等待(即被阻止),直到該對象被釋放。2) AutoResetEvent 也沒有問題
AutoResetEvent aa = new AutoResetEvent(true);
public void a()
{
for (int i = 0; i < 4; i++)
{
Thread.Sleep(800);
}
aa.Set();
} -
用catch的確可以,我運行了一晚都很“正常”,但我從數據庫中看來,就有部分的執行被漏掉了,我是每隔5秒執行一次的 -
在catch中依舊會拋出“從不同步的代碼塊中調用了對象同步方法。”請問有根本的解決方法嗎
-
我覺得應該是C#的一個bug吧,應該TryEnter返回為False后不允許進入后面執行的代碼