为什么EventWaitHandle不起作用
本文关键字:不起作用 EventWaitHandle 为什么 | 更新日期: 2023-09-27 18:19:34
我有两个名为ChangeText()&ChangeColor(),第一个名为ChangeText的函数,它会将大量数据加载到内存中,这将花费大量时间,所以我异步运行它;另一个名为ChangeColor,当数据加载正常时,他将更改按钮的颜色,因此需要运行这两个函数:首先是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;
}
}
}
这是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);
}
}
}
我计划使用EventWaitHandle来同步这两个函数,但结果是这两个功能仍将以混乱的顺序运行:有时先运行ChangeText()函数,有时先运行ChangeColor()函数。我太困惑了。
此外,我使用ThreadPool来启动这两个函数,但为什么我得到了相同的threadID,如下所示:
装载完成!(Thread.CurrentThreadName=10)着色完成!(线程.CurrentThreadName=10)
我认为Thread.CurrentThreadName会有所不同,因为我使用了线程池!!!为什么?谢谢你的回答。
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;
}
}
请参阅上面的代码片段,它应该会对您进行一些解释。当然,您有相同的线程名称,因为您将标签委托发送到UI线程-这是您不应该像最初那样在那里进行任何冗长操作的主要原因
关于您的问题(我在代码中看到了其他可能的问题),我会尝试在构造时设置事件处理程序,并删除Change_Text
方法的waitMeHandle.Reset();
。
当您并行启动这两个进程时,您不能确定Change_Text
是否会首先执行。
关于执行线程名称的问题:
如果调用Dispatcher.Invoke
,则指定的委托将在Dispatcher关联的线程上执行。在您的情况下,可能是UI线程。
请参阅MSDN上的备注部分:
在WPF中,只有创建DispatcherObject的线程才能访问该对象。例如,从主UI线程分离出来的后台线程无法更新在UI线程上创建的Button的内容。为了让后台线程访问按钮的Content属性,后台线程必须将工作委托给与UI线程关联的Dispatcher。这是通过使用Invoke或BeginInvoke来完成的。
接下来,你做得太过火了。如果您调用ThreadPool.QueueUserWorkItem
,那么您正在安排一个委托在ThreadPool线程上执行。现在,在您的代码中,如果在ThreadPool线程上执行的方法中,您调用Func<T>.BeginInvoke
,然后再次调度一个委托在ThreadPool线程上执行。所以只需将您的代码更改为:
private void button1_Click(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem(o => ChangeText());
ThreadPool.QueueUserWorkItem(o => ChangeColor());
label1.Content += " 'r'n-------------------------'r'n";
}
足以在ThreadPool线程上执行ChangeText
和ChangeColor
。