这是 .net Monitor/lock 语句中的错误还是 MessageBox.Show 的行为不同?
题
想象一下,获胜表单上有两个按钮。您认为当用户使用下面的代码按下“按钮 1”时应该有什么行为?
它应该一次性显示所有 5 个消息框,还是一一显示 - MessageBox.Show 语句位于锁定语句内?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private static readonly object lockobject = new object();
private void button1_Click(object sender, EventArgs e)
{
var action = new Action(function);
for(int i = 0; i< 5; i++)
{
action.BeginInvoke(null, null);
}
}
private void function()
{
if (button2.InvokeRequired)
{
var func = new Action(function);
button2.Invoke(func);
}
else
{
lock (lockobject)
{
MessageBox.Show("Testing");
}
}
}
}
现在,如果我们将 MessageBox.Show 替换为任何其他语句,它将一次只执行一个语句,其他线程将等待,一次一个。
解决方案
由于当InvokeRequired为假时,执行你的lock语句,锁会在同一个(主)线程中运行。因此,锁将不阻塞。
如果要在MessageBox阻断,使用的ShowDialog代替。
其他提示
lock 仅在另一个线程拥有该锁时才会阻塞,允许同一线程多次锁定同一对象 - 否则这将是一个即时死锁,毕竟它会在等待当前线程时阻塞当前线程。
Control.BeginInvoke 不在不同的线程中执行代码,它将始终执行为控件泵送消息的线程中的代码,它通过将消息发布到控件的输入队列,然后在消息到达时执行代码来实现。
因为 2 你的代码根本不是多线程的,所有东西都在同一个线程中执行 - 这让我们回到了 1,当你没有多线程锁时什么也不做。
我怀疑UI线程在MessageBox生命周期期间泵送消息。因为锁被重入(和UI线程每次运行代码),这会导致上述情况。 也许尝试使所述所有者( this
)到消息框? (我将尝试在秒...)
您可以更有力地阻止它,但是这将阻止画(“没有响应”等)。
我同意尼尔。你改变你的函数下面的一个后,你可以测试你是在同一个线程上运行(这并不奇怪):
private void function()
{
if (button2.InvokeRequired)
{
var func = new Action(function);
button2.Invoke(func);
}
else
{
lock (lockobject)
{
int threadId = Thread.CurrentThread.ManagedThreadId;
MessageBox.Show("Testing. Running on thread "+threadId);
}
}
}
所以在这里,因为你的UI线程是由于锁,它不会阻止。底线是STA线程不是具有适当的多线程编程兼容。
不隶属于 StackOverflow