C#多線程問題(從不同步的代碼塊中調用了對象同步方法。)


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.  
  2.  

    1)嘗試用lock
    2)推薦用Autoeventset 

      

     

  3.  


    用過lock,問題更嚴重,基本上每點擊都出錯。Autoeventset能詳細說明一下嗎?

      

     

  4.  

    使用   Monitor   鎖定對象(即引用類型)而不是值類型。將值類型變量傳遞給   Enter   時,它被裝箱為對象。如果再次將相同的變量傳遞給   Enter,則它被裝箱為一個單獨對象,而且線程不會阻止。Monitor   本應保護的代碼未受保護。此外,將變量傳遞給   Exit   時,也創建了另一個單獨對象。因為傳遞給   Exit   的對象和傳遞給   Enter   的對象不同,Monitor   將引發   SynchronizationLockException

      

     

  5.  

    這個可能是你用TRYENTER的原因,這個東西不能確保你得到排他鎖,所以你在這里要進行異常判斷。MSDN也是這樣要求的。我估計可能是在沒有EXIT時你去獲取了鎖而沒有成功,緊接着馬上EXIT,於是又一個線程進入。形成兩個線程競爭。

      

     

  6.  

    我估計你增加一個判斷,如果沒有得到便RETURN結束新生成的線程。可能會變好。

      

     

  7.  

      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);
                }
            }

      

     

  8.  

    我做了測試,沒問題了。呵呵。原理是按樓上所說,但分析可能是我所想。看樣子還是那句話,多看MSDN

      

     

  9.  

    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();
            
            } 

      

     

  10.  


    用catch的確可以,我運行了一晚都很“正常”,但我從數據庫中看來,就有部分的執行被漏掉了,我是每隔5秒執行一次的

      

     

  11.  

    在catch中依舊會拋出“從不同步的代碼塊中調用了對象同步方法。”請問有根本的解決方法嗎

      

     

  12.  

    我覺得應該是C#的一個bug吧,應該TryEnter返回為False后不允許進入后面執行的代碼

      


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM