4

想象一下,您在赢单上有两个按钮。当用户使用以下代码按下“按钮 1”时,您认为应该是什么行为?

它应该一次显示所有 5 个消息框,还是一个一个地显示 - MessageBox.Show 语句在 lock 语句中?

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 替换为任何其他语句,它将一次只执行一个语句,其他线程将等待,一次一个。

4

4 回答 4

4

由于您的 lock 语句在 InvokeRequired 为 false 时执行,因此锁将全部在同一个(主)线程上运行。因此锁不会阻塞。

如果要阻止 MessageBox,请改用 ShowDialog。

于 2009-02-25T10:58:27.313 回答
2
  1. lock 仅在另一个线程拥有锁的情况下才阻塞,允许从同一个线程多次锁定同一个对象 - 否则这将是一个即时死锁,毕竟它会在等待当前线程时阻塞当前线程。

  2. Control.BeginInvoke 不会在不同的线程中执行代码,它总是会执行线程中的代码,为控件泵送消息,它通过将消息发布到控件的输入队列然后在消息到达时执行代码来执行此操作。

因为 2 你的代码根本不是多线程的,所以一切都在同一个线程中执行 - 这让我们回到 1,当你没有多个线程时 lock 什么都不做。

于 2009-02-25T12:15:56.643 回答
0

我怀疑 UI 线程在 MessageBox 生命周期中发送消息。因为锁是可重入的(并且UI线程每次都在运行代码),这会导致上述情况。也许尝试将所有者(this)传递到消息框?(我会在几秒钟内尝试......)

您可以更有力地阻止它,但这会阻止绘画(“不响应”等)。

于 2009-02-25T10:50:53.117 回答
0

我同意尼尔。将函数更改为以下函数后,您可以测试您是否在同一线程上运行(不足为奇):

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 线程与正确的多线程编程不兼容。

于 2009-02-25T12:20:46.677 回答