想象一下,胜利表格上有两个按钮。当用户使用以下代码按下“按钮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替换为任何其他语句,它将一次只执行一个语句,其他线程将一次执行一个语句。
答案 0 :(得分:4)
由于当InvokeRequired为false时执行lock语句,因此锁将全部在同一(主)线程上运行。因此锁不会阻塞。
如果要阻止MessageBox,请改用ShowDialog。
答案 1 :(得分:2)
如果另一个线程拥有锁,则只锁定块,允许多次从同一个线程锁定同一个对象 - 否则它将是一个即时死锁,毕竟它会在等待时阻塞当前线程对于当前的线程。
Control.BeginInvoke不执行不同线程中的代码,它总是执行控件的线程泵送消息中的代码,它通过向控件的输入队列发送消息然后执行消息到达时的代码。
因为你的代码根本不是多线程的,所以一切都在同一个线程中执行 - 这使我们回到1,当你没有多个线程时,lock什么都不做。
答案 2 :(得分:0)
我怀疑UI线程在MessageBox生命周期中正在传递消息。因为锁是可重入的(并且UI线程每次都运行代码),这导致了上述情况。 也许尝试将所有者(。this
)传递到消息框中? (我会在一秒钟内尝试......)
你可以更有力地阻止它,但这将阻止绘画(“没有响应”等)。
答案 3 :(得分:0)
我同意Nir。将功能更改为下面的功能后,您可以测试您在同一个线程上运行(不出意外):
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线程与正确的多线程编程不兼容。