You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用EventWaitHandle与Dispatcher.BeginInvoke调度的线程同步异常问询

问题根源分析:UI异步调用的竞态,而非EventWaitHandle的问题

哈哈,这个坑我之前也踩过!首先得澄清:EventWaitHandle本身的同步逻辑完全没问题,你遇到的问题是因为工作线程(t00)的写入操作和后续修改共享变量的操作之间,存在隐形的竞态条件——大概率是你用了异步的UI调用(比如BeginInvoke)导致的。

先还原你大概率的代码场景

假设你的核心逻辑大概是这样(完全符合你描述的现象):

private string _sharedStr = "y";
private EventWaitHandle _evt = new AutoResetEvent(false);

void LaunchThreads()
{
    Thread t00 = new Thread(WriteToTextBoxY);
    Thread t01 = new Thread(WriteToTextBoxX);
    t00.Start();
    t01.Start();
}

void WriteToTextBoxY()
{
    for (int i = 0; i < 20; i++)
    {
        // 重点:如果用的是BeginInvoke(异步投递UI请求)
        textBox1.BeginInvoke(new Action(() => textBox1.Text += _sharedStr));
    }
    _sharedStr = "x"; // 修改共享变量
    _evt.Set(); // 通知t01启动
}

void WriteToTextBoxX()
{
    _evt.WaitOne();
    for (int i = 0; i < 20; i++)
    {
        textBox2.Invoke(new Action(() => textBox2.Text += _sharedStr));
    }
}

为什么会出现19次y+1次x?

当t00执行最后一次BeginInvoke时,它只是把“写入文本框”的请求丢进UI线程的消息队列,然后不等UI线程执行这个请求,就直接继续跑后面的代码:把_sharedStr改成x,再触发Event通知t01。

等UI线程终于轮到处理最后一次写入请求时,_sharedStr已经被改成x了——所以最后一次写入的自然是x,就出现了你看到的19次y+1次x的现象。

为什么加Thread.Sleep()能解决?

加Sleep相当于给了UI线程一段“缓冲时间”,让它来得及把t00投递的所有20次写入请求都处理完毕,之后t00才会修改_sharedStr。这时候最后一次写入已经用的是修改前的y,自然就正常了。

正确的解决方式(不要依赖Sleep这种临时hack)

Sleep只是凑活的 workaround,推荐两种靠谱的解法:

  1. 把异步调用换成同步调用:用Invoke替代BeginInvoke。Invoke会阻塞工作线程,直到UI线程完成写入操作,再继续执行后续代码。这样最后一次写入完成后,才会修改_sharedStr,完全避免竞态。
  2. 等待所有异步写入请求完成:如果必须用异步调用,可以用Task包装每个写入操作,然后等待所有任务完成后再修改变量:
async void WriteToTextBoxY()
{
    var writeTasks = new List<Task>();
    for (int i = 0; i < 20; i++)
    {
        // 用Task包装Invoke,收集所有任务
        writeTasks.Add(Task.Run(() => textBox1.Invoke(() => textBox1.Text += _sharedStr)));
    }
    await Task.WhenAll(writeTasks); // 等待所有写入完成
    _sharedStr = "x";
    _evt.Set();
}

内容的提问来源于stack exchange,提问作者KMC

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:56:25