C# 为什么EventWaitHandle不起作用?

C# 为什么EventWaitHandle不起作用?,c#,threadpool,C#,Threadpool,我有两个名为ChangeText()&ChangeColor()的函数,第一个名为ChangeText的函数将大量数据加载到内存中,这将花费大量时间,因此我异步运行它;另一个称为ChangeColor,当数据加载ok时,他将更改按钮的颜色,因此有一个命令来运行这两个函数:首先是ChangeText,然后是ChangeColor。这是我的密码: using System; using System.Text; using System.Windows; using System.Windows.M

我有两个名为ChangeText()&ChangeColor()的函数,第一个名为ChangeText的函数将大量数据加载到内存中,这将花费大量时间,因此我异步运行它;另一个称为ChangeColor,当数据加载ok时,他将更改按钮的颜色,因此有一个命令来运行这两个函数:首先是ChangeText,然后是ChangeColor。这是我的密码:

using System;
using System.Text;
using System.Windows;
using System.Windows.Media;
using System.Threading;
using System.IO;

namespace ThreadSynchorous
{
    public partial class Window1 : Window
    {
        public Window1()
        {
        InitializeComponent();
        asyncInvoke = new AsyncInvoke();
    }
    AsyncInvoke asyncInvoke;
    EventWaitHandle waitMeHandle = new EventWaitHandle(false,EventResetMode.ManualReset);

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state)
        {
            asyncInvoke.BeginAsync(ChangeText);
        }), null);

        ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state)
        {
            asyncInvoke.BeginAsync(ChangeColor);
        }), null);

        label1.Content += " \r\n-------------------------\r\n";
    }

    private bool ChangeText()
    {
        waitMeHandle.Reset();
        this.button1.Dispatcher.Invoke(new Func<bool>(delegate()
        {
            string filename = @"C:\EXO.txt";
            using (StreamReader sr = new StreamReader(filename, Encoding.Default))
            {
                string result;
                while ((result = sr.ReadLine()) != null)
                {
                    //here perform action
                }
            }

            label1.Dispatcher.Invoke(new Func<bool>(delegate
            {
                label1.Content += "Loading finish!(Thread.CurrentThreadName="+Thread.CurrentThread.ManagedThreadId.ToString()+") ";
                waitMeHandle.Set();
                return true;
            }));
            waitMeHandle.Set();
            return true;
        }));
        waitMeHandle.Set();
        return true;
    }

    private bool ChangeColor()
    {
        waitMeHandle.WaitOne();
        this.button1.Dispatcher.Invoke(new Func<bool>(delegate()
        {
            this.button1.Background = Brushes.Red;

            label1.Dispatcher.Invoke(new Func<bool>(delegate()
            {
                label1.Content += "Coloring finish!(Thread.CurrentThreadName="+Thread.CurrentThread.ManagedThreadId+") ";
                return true;
            }));

            return true;
        }));
        return true;
    }
}
}
使用系统;
使用系统文本;
使用System.Windows;
使用System.Windows.Media;
使用系统线程;
使用System.IO;
名称空间线程同步
{
公共部分类Window1:Window
{
公共窗口1()
{
初始化组件();
asyncInvoke=新的asyncInvoke();
}
异步调用异步调用;
EventWaitHandle waitMeHandle=新的EventWaitHandle(错误,EventResetMode.ManualReset);
私有无效按钮1\u单击(对象发送者,路由目标)
{
ThreadPool.QueueUserWorkItem(新的WaitCallback(委托)(对象状态)
{
asyncInvoke.BeginAsync(ChangeText);
}),空);
ThreadPool.QueueUserWorkItem(新的WaitCallback(委托)(对象状态)
{
asyncInvoke.BeginAsync(ChangeColor);
}),空);
label1.Content+=“\r\n--------------------\r\n”;
}
私有boolchangetext()
{
waitMeHandle.Reset();
this.button1.Dispatcher.Invoke(新函数(委托)()
{
字符串文件名=@“C:\EXO.txt”;
使用(StreamReader sr=new StreamReader(文件名,Encoding.Default))
{
字符串结果;
而((result=sr.ReadLine())!=null)
{
//在这里执行操作
}
}
label1.Dispatcher.Invoke(新函数(委托
{
label1.Content+=“加载完成!”(Thread.CurrentThreadName=“+Thread.CurrentThread.ManagedThreadId.ToString()+”);
waitMeHandle.Set();
返回true;
}));
waitMeHandle.Set();
返回true;
}));
waitMeHandle.Set();
返回true;
}
私有bool ChangeColor()
{
waitMeHandle.WaitOne();
this.button1.Dispatcher.Invoke(新函数(委托)()
{
this.button1.Background=画笔.红色;
label1.Dispatcher.Invoke(新函数(委托)()
{
label1.Content+=“着色完成!(Thread.CurrentThreadName=“+Thread.CurrentThread.ManagedThreadId+”);
返回true;
}));
返回true;
}));
返回true;
}
}
}
以下是AsyncInvoke的类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ThreadSynchorous
{
    public  class AsyncInvoke
    {
        public void BeginAsync(Func<bool> MyFunction)
        {
            Func<bool> func = new Func<bool>(MyFunction);
            IAsyncResult iar = func.BeginInvoke(new AsyncCallback(EndAsync), func);
        }

        public void EndAsync(IAsyncResult iar)
        {
            Func<bool> func = (Func<bool>)iar.AsyncState;
            func.EndInvoke(iar);
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
名称空间线程同步
{
公共类异步调用
{
public void BeginAsync(Func MyFunction)
{
Func Func=新函数(MyFunction);
IAsyncResult iar=func.BeginInvoke(新的异步回调(EndAsync),func);
}
public void EndAsync(IAsyncResult iar)
{
Func Func=(Func)iar.AsyncState;
函数EndInvoke(iar);
}
}
}
我计划使用EventWaitHandle来同步这两个函数,但结果是这两个函数仍将以混乱的顺序运行:有时先执行ChangeText()函数,有时先执行ChangeColor()。我只是很困惑

另外,我使用ThreadPool启动这两个函数,但为什么我得到了相同的threadID,如下所示:
装载完毕!(Thread.CurrentThreadName=10)着色完成!(Thread.CurrentThreadName=10)

我认为Thread.CurrentThreadName会有所不同,因为我使用threadpool!!!为什么?谢谢你的回答。

关于你的问题(我看到了代码中可能存在的其他问题),我会尝试在构造时设置事件处理程序,并删除
waitMeHandle.Reset()Change\u Text
方法的code>

当您并行启动这两个进程时,您无法确保首先执行
Change\u Text

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        asyncInvoke = new AsyncInvoke();
    }
    AsyncInvoke asyncInvoke;
    EventWaitHandle waitMeHandle = new EventWaitHandle(false, EventResetMode.ManualReset);

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state)
        {
            asyncInvoke.BeginAsync(ChangeText);
        }), null);

        ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state)
        {
            asyncInvoke.BeginAsync(ChangeColor);
        }), null);

        label1.Content += " \r\n-------------------------\r\n";
    }

    private bool ChangeText()
    {
        Debug.WriteLine("ChangeText");         

        //do your time-consuming operation here, controls' delegated are for UI updates only

        this.button1.Dispatcher.Invoke((Action)(()=>
        {
            Thread.Sleep(2000);
            Debug.WriteLine("Button invoker");
            //update button here


            //what was bool return type for?
            label1.Dispatcher.Invoke((Action)(() =>
            {
                label1.Content += "Loading finish!(Thread.CurrentThreadName=" + Thread.CurrentThread.ManagedThreadId.ToString() + ") ";
                waitMeHandle.Set();
            }));

        }));


        //waitMeHandle.Set(); - here's your guilty - button delegate runs asynchrounously so you had absolutely no guarantee that it's done as your app reach this line
        return true;
    }

    private bool ChangeColor()
    {
        waitMeHandle.WaitOne();
        Debug.WriteLine("ChangeColor");
        this.button1.Dispatcher.Invoke((Action)(() =>
        {
            this.button1.Background = Brushes.Red;

            label1.Dispatcher.Invoke((Action)(() =>
            {
                label1.Content += "Coloring finish!(Thread.CurrentThreadName=" + Thread.CurrentThread.ManagedThreadId + ") ";
                waitMeHandle.Reset(); //you've consumed your event here so this is the place to reset it
            }));
        }));
        return true;
    }
}

请参阅上面的代码片段-它应该会对您进行一些解释。当然,您有相同的线程名称,因为您将label delegate分派给UI线程-这是您不应该像最初那样在那里执行任何冗长操作的主要原因,因为关于执行线程名称的问题如下所示:

如果调用
Dispatcher.Invoke
,则指定的委托将在与Dispatcher关联的线程上执行。在您的情况下,可能是UI线程

见以下备注部分:

在WPF中,只有创建DispatcherObject的线程才能访问该对象。例如,从主UI线程派生的后台线程无法更新在UI线程上创建的按钮的内容。为了让后台线程访问按钮的内容属性,后台线程必须将工作委托给与UI线程关联的调度程序。这是通过使用Invoke或BeginInvoke来实现的

其次,你做得太过分了。如果调用
ThreadPool.QueueUserWorkItem
,则您正在安排一个委托在ThreadPool线程上执行。现在,在代码中,如果在线程池线程上执行的方法中,调用
Func.BeginInvoke
,然后再次计划在线程池线程上执行委托。因此,只需将代码更改为:

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        ThreadPool.QueueUserWorkItem(o => ChangeText());

        ThreadPool.QueueUserWorkItem(o => ChangeColor());

        label1.Content += " \r\n-------------------------\r\n";
    }

足够在线程池线程上执行
ChangeText
ChangeColor

Thx,以便在删除waitMeHandle.Reset()后获得SoMos的回复;它仍然不能正常工作。即使这两个进程并行运行,为什么我仍然不能使用EventWaitHandle来控制?你有什么好的解决办法吗?比如使用互斥、连接或者其他什么?你能帮我吗