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

        
  • 相关阅读:
    Java中变量的使用规则
    Java中的数据类型
    如何命名Java变量
    thinkphp3.2 验证码生成和点击刷新验证码
    workerman
    jorgchart,帮助你生成组织结构图的
    PHP代码获取客户端IP地址经纬度及所在城市
    百度API城市代码CityCode官方文档
    自定义过滤器
    内置过滤器
  • 原文地址:https://www.cnblogs.com/grj001/p/12223685.html
Copyright © 2020-2023  润新知