这是.net Monitor / lock语句中的错误,还是MessageBox.Show的行为有所不同?

时间:2009-02-25 10:47:02

标签: c# .net locking monitor

想象一下,胜利表格上有两个按钮。当用户使用以下代码按下“按钮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替换为任何其他语句,它将一次只执行一个语句,其他线程将一次执行一个语句。

4 个答案:

答案 0 :(得分:4)

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

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

答案 1 :(得分:2)

  1. 如果另一个线程拥有锁,则只锁定块,允许多次从同一个线程锁定同一个对象 - 否则它将是一个即时死锁,毕竟它会在等待时阻塞当前线程对于当前的线程。

  2. Control.BeginInvoke不执行不同线程中的代码,它总是执行控件的线程泵送消息中的代码,它通过向控件的输入队列发送消息然后执行消息到达时的代码。

  3. 因为你的代码根本不是多线程的,所以一切都在同一个线程中执行 - 这使我们回到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线程与正确的多线程编程不兼容。