C#多线程问题(从不同步的代码块中调用了对象同步方法。)

hzhsky1985 2009-01-12 03:35:39
代码如下:
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里面的。请问高手为什么会引发这个问题?怎样解决?
...全文
2900 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
十四州 2011-10-23
  • 打赏
  • 举报
回复
我觉得应该是C#的一个bug吧,应该TryEnter返回为False后不允许进入后面执行的代码
zeng8786052 2009-07-24
  • 打赏
  • 举报
回复
我估计可能是锁太多而没有很好的控制好!仔细检查代码,可能会有发现!
hzhsky1985 2009-01-13
  • 打赏
  • 举报
回复
在catch中依旧会抛出“从不同步的代码块中调用了对象同步方法。”请问有根本的解决方法吗
hzhsky1985 2009-01-13
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 fpcc 的回复:]
这个可能是你用TRYENTER的原因,这个东西不能确保你得到排他锁,所以你在这里要进行异常判断。MSDN也是这样要求的。我估计可能是在没有EXIT时你去获取了锁而没有成功,紧接着马上EXIT,于是又一个线程进入。形成两个线程竞争。
[/Quote]

用catch的确可以,我运行了一晚都很“正常”,但我从数据库中看来,就有部分的执行被漏掉了,我是每隔5秒执行一次的
human_2 2009-01-12
  • 打赏
  • 举报
回复


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

}
fpcc 2009-01-12
  • 打赏
  • 举报
回复
我做了测试,没问题了。呵呵。原理是按楼上所说,但分析可能是我所想。看样子还是那句话,多看MSDN
优途科技 2009-01-12
  • 打赏
  • 举报
回复
建议通过代理来实现。
优途科技 2009-01-12
  • 打赏
  • 举报
回复
你是将一段代码放到多个线程中去执行,这样肯定是不行的了。
dayizhixiaotutu 2009-01-12
  • 打赏
  • 举报
回复
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);
}
}
fpcc 2009-01-12
  • 打赏
  • 举报
回复
我估计你增加一个判断,如果没有得到便RETURN结束新生成的线程。可能会变好。
fpcc 2009-01-12
  • 打赏
  • 举报
回复
这个可能是你用TRYENTER的原因,这个东西不能确保你得到排他锁,所以你在这里要进行异常判断。MSDN也是这样要求的。我估计可能是在没有EXIT时你去获取了锁而没有成功,紧接着马上EXIT,于是又一个线程进入。形成两个线程竞争。
dayizhixiaotutu 2009-01-12
  • 打赏
  • 举报
回复
使用 Monitor 锁定对象(即引用类型)而不是值类型。将值类型变量传递给 Enter 时,它被装箱为对象。如果再次将相同的变量传递给 Enter,则它被装箱为一个单独对象,而且线程不会阻止。Monitor 本应保护的代码未受保护。此外,将变量传递给 Exit 时,也创建了另一个单独对象。因为传递给 Exit 的对象和传递给 Enter 的对象不同,Monitor 将引发 SynchronizationLockException
hzhsky1985 2009-01-12
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 human_2 的回复:]
1)尝试用lock
2)推荐用Autoeventset
[/Quote]

用过lock,问题更严重,基本上每点击都出错。Autoeventset能详细说明一下吗?
human_2 2009-01-12
  • 打赏
  • 举报
回复
1)尝试用lock
2)推荐用Autoeventset

111,076

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧