zoukankan      html  css  js  c++  java
  • 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后不允许进入后面执行的代码

        
  • 相关阅读:
    USACO Milk2 区间合并
    Codeforces 490B Queue【模拟】
    HDU 3974 Assign the task 简单搜索
    HDU 5119 Happy Matt Friends(2014北京区域赛现场赛H题 裸背包DP)
    Cin、Cout 加快效率方法
    POJ 1159 回文LCS滚动数组优化
    POJ 2479 不相交最大子段和
    POJ 1458 最长公共子序列 LCS
    在阿里最深刻的,还是职场之道给我的震撼
    精细化
  • 原文地址:https://www.cnblogs.com/grj001/p/12223686.html
Copyright © 2011-2022 走看看