1

以下代码有两个线程,每个线程将 20 写入string str其相应的文本框。完成后,Thread t00发出Thread t01启动信号并将共享string stry更改为xThread t00应将 20 y写入文本框,并将Thread t0120 x写入另一个文本框。相反,Thread t00最终写 19 y和 1 x。但是,如果我Thread.Sleep()在设置 EventWaitHandle 之前添加一个,则可以解决我遇到的问题(我得到 20 x和 20 y),但是为什么呢?EventWaitHandle不应该只在循环完成后设置,有或没有Thread.Sleep().

public partial class MainWindow : Window
{
    public string str = "y";
    static EventWaitHandle _waitHandle = new AutoResetEvent(false);

    public MainWindow()
    {
        InitializeComponent();

        Thread t00 = new Thread(() =>
        {
            for (int i = 0; i < 20; i++)
            {
                Thread.Sleep(200);
                Action action00 = () =>
                {
                    tb00.AppendText(str);
                };
                Dispatcher.BeginInvoke(action00);
            }
            Thread.Sleep(200);  // <-- why this fix the problem??
            _waitHandle.Set();
        });
        t00.Start();


        Thread t01 = new Thread(() =>
        {
            Action action00 = () =>
            {
                tb01.AppendText("Waiting...\n");
            };
            Dispatcher.BeginInvoke(action00);
            _waitHandle.WaitOne();

            str = "x";
            for (int i = 0; i < 20; i++)
            {
                Thread.Sleep(200);
                Action action = () =>
                {
                    tb01.AppendText(str);
                };
                Dispatcher.BeginInvoke(action);
            }
        });
        t01.Start();
    }
}

在此处输入图像描述

4

2 回答 2

1

因为你正在使用BeginInvoke. BeginInvoke异步调用 UI 线程上的委托。它将消息放入 UI 线程消息队列并返回,因此它返回的事实并不意味着实际执行了操作。

因此,在大多数情况下,当您设置等待句柄并且另一个线程接收信号并stryto更改时x- UI 线程队列中仍然存在未调用的tb00.AppendText(str);委托。当它最终被调用时——str已经是x

Thread.Sleep“修复”该问题,因为它为该待处理委托在 UI 线程上执行提供了一些时间。使用Invoke而不是BeginInvoke“修复”它,因为Invoke它是同步的,并且仅在委托实际在 UI 线程上执行后才返回。

于 2018-03-20T05:35:24.887 回答
1

考虑BeginInvoke()将一个工作单元推入队列。当 20thaction00从工作队列中弹出并执行时,str='x'已经执行了,所以当action00实际运行时,它会打印一个x.

在执行之前Thread.Sleep(200)第 20action00次弹出并运行str='x',因此它将打印一个y.

于 2018-03-20T05:40:39.543 回答