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