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

发布于 2024-07-13 18:13:56 字数 907 浏览 7 评论 0原文

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

Imagine you have two buttons on the win form. What do you think should be the behavior when user presses the "button 1" with the below code?

Should it display all 5 message box in one go, or one by one - MessageBox.Show statement is inside a lock statement?

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");
            }
        }
    }
}

Now if we replace MessageBox.Show with any other statment, it would execute the statement only one at a time, the other threads would wait, one at a time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

鱼忆七猫命九 2024-07-20 18:13:56

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

如果您希望 MessageBox 被阻止,请使用 ShowDialog。

Since your lock statement is executed when InvokeRequired is false, the locks will all run on the same (main) thread. Therefore the locks will not block.

If you want the MessageBox to block, use ShowDialog instead.

Smile简单爱 2024-07-20 18:13:56
  1. lock 仅在另一个线程拥有该锁时才会阻塞,允许同一线程多次锁定同一对象 - 否则这将是一个即时死锁,毕竟它会在等待当前线程时阻塞当前线程thread.

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

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

  1. lock only blocks if another thread owns the lock, locking on the same object from the same thread multiple times is allowed - otherwise it would be an instant deadlock, after all it would have been blocking the current thread while waiting for the current thread.

  2. Control.BeginInvoke doesn't execute code in a different thread, it will always execute the code in the thread pumping messages for the control, it does so by posting a message to the control's input queue and then executing the code when the message arrives.

because of 2 your code isn't multi-threaded at all, everything executes in the same thread - and this brings us back to 1, when you don't have multiple threads lock does nothing.

毁虫ゝ 2024-07-20 18:13:56

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

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

I suspect the UI thread is pumping messages during the MessageBox life-cycle. Because locks are re-entrant (and the UI thread is running the code each time), this causes the above. Perhaps try passing the owner (this) into the message-box? (I'll try in a sec...).

You could block it more forcefully, but that will block painting ("not responding" etc).

深居我梦 2024-07-20 18:13:56

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

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

I agree with Nir. After you change your function to the one below, you can test that you are running on the same thread (not surprisingly):

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

So here because your UI thread is owing the lock, it doesn't get blocked. The bottom line is that STA threads are not compatible with proper multithreaded programming.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文