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后不允许进入后面执行的代码

      
原文地址:https://www.cnblogs.com/grj001/p/12223686.html