C# 线程完成时与UI线程通信
下面我有一个简单的程序,有两个线程执行一些任务 Thread1是数据馈送器。Thread2是数据处理器 到目前为止,通过我的方法完成的工作是有效的,但我希望在工作完成时有更好的方式得到通知 这是密码C# 线程完成时与UI线程通信,c#,multithreading,C#,Multithreading,下面我有一个简单的程序,有两个线程执行一些任务 Thread1是数据馈送器。Thread2是数据处理器 到目前为止,通过我的方法完成的工作是有效的,但我希望在工作完成时有更好的方式得到通知 这是密码 class Program { private static BlockingCollection<int> _samples = new BlockingCollection<int>(); private static CancellationToken
class Program
{
private static BlockingCollection<int> _samples = new BlockingCollection<int>();
private static CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private static bool _cancel;
static void Main(string[] args)
{
ThreadStart thread1 = delegate
{
ProcessThread1();
};
new Thread(thread1).Start();
ThreadStart thread2 = delegate
{
ProcessThread2();
};
new Thread(thread2).Start();
Console.WriteLine("Press any key to cancel..");
Console.Read();
_cancel = true;
_cancellationTokenSource.Cancel();
Console.Read();
}
private static void ProcessThread1()
{
for (int i = 0; i < 10; i++)
{
if (_cancel)
{
break;
}
Console.WriteLine("Adding data..");
_samples.TryAdd(i,100);
Thread.Sleep(1000);
}
// I dont like this. Instead can I get notified in the UI thread that this thread is complete.
_cancel = true;
_cancellationTokenSource.Cancel();
}
private static void ProcessThread2()
{
while (!_cancellationTokenSource.IsCancellationRequested)
{
int data;
if (_samples.TryTake(out data, 100))
{
// Do some work.
Console.WriteLine("Processing data..");
}
}
Console.WriteLine("Cancelled.");
}
}
类程序
{
私有静态BlockingCollection_samples=新BlockingCollection();
私有静态CancellationTokenSource _CancellationTokenSource=new CancellationTokenSource();
私有静态bool\u cancel;
静态void Main(字符串[]参数)
{
ThreadStart thread1=委托
{
ProcessThread1();
};
新线程(thread1.Start();
ThreadStart thread2=委托
{
ProcessThread2();
};
新线程(thread2.Start();
Console.WriteLine(“按任意键取消…”);
Console.Read();
_取消=真;
_cancellationTokenSource.Cancel();
Console.Read();
}
私有静态void ProcessThread1()
{
对于(int i=0;i<10;i++)
{
如果(取消)
{
打破
}
Console.WriteLine(“添加数据…”);
_样本.TryAdd(i,100);
睡眠(1000);
}
//我不喜欢这样。相反,我可以在UI线程中得到通知,该线程已完成。
_取消=真;
_cancellationTokenSource.Cancel();
}
私有静态void ProcessThread2()
{
而(!\u cancellationTokenSource.IsCancellationRequested)
{
int数据;
如果(_samples.TryTake(输出数据,100))
{
//做一些工作。
Console.WriteLine(“处理数据…”);
}
}
控制台。写入线(“取消”);
}
}
如果用户请求取消或工作完成,我希望程序退出
我不确定当ProcessThread1用完时如何得到通知。目前,当工作完成时,我正在设置cancel=true,但它似乎不正确。非常感谢您的帮助。如果您使用
任务而不是手动创建线程,您可以在任务上附加一个延续,以通知UI工作已完成
Task workOne = Task.Factory.StartNew( () => ProcessThread1());
workOne.ContinueWith(t =>
{
// Update UI here
}, TaskScheduler.FromCurrentSynchronizationContext());
使用.NET 4.5,这变得更加容易,因为您可以潜在地使用新的async
语言支持:
var workOne = Task.Run(ProcessThread1);
var workTwo = Task.Run(ProcessThread2);
// asynchronously wait for both tasks to complete...
await Task.WhenAll(workOne, workTwo);
// Update UI here.
请注意,这两者的设计都考虑了用户界面,并且在控制台应用程序中的行为会异常,因为控制台应用程序中没有当前的同步上下文。当您将其移动到真正的用户界面时,它将正常工作。再启动一个线程,其唯一任务是等待控制台输入:
private void ConsoleInputProc()
{
Console.Write("Press Enter to cancel:");
Console.ReadLine();
_cancellationTokenSource.Cancel();
}
然后,主线程启动两个处理线程和输入线程
// create and start the processing threads
Thread t1 = new Thread(thread1);
Thread t2 = new Thread(thread2);
t1.Start();
t2.Start();
// create and start the input thread
Thread inputThread = new Thread(ConsoleInputProc);
inputThread.Start();
然后,等待两个处理线程:
t1.Join();
// first thread finished. Request cancellation.
_cancellationTokenSource.Cancel();
t2.Join();
因此,如果用户按Enter键,那么输入线程将设置取消标志。thread1和thread2都会看到取消请求并退出
如果thread1完成其工作,则主线程设置取消标志,thread2将取消
在这两种情况下,直到线程2退出,程序才会退出
没有必要显式地终止输入线程。当程序退出时,它将死亡
顺便说一下,我将从Thread1进程中删除以下行:
// I dont like this. Instead can I get notified in the UI thread that this thread is complete.
_cancel = true;
_cancellationTokenSource.Cancel();
我将删除\u cancel
变量,并像第二个线程一样,让第一个线程检查IsCancellationRequested
不幸的是,您必须启动一个专用线程来等待控制台输入,但这是我所知道的实现这一点的唯一方法。Windows控制台似乎没有可等待的事件
请注意,您可以使用任务
执行相同的操作,总体上更易于使用。任务执行的代码是相同的
更新
从更大的角度来看,我发现您有一个典型的生产者/消费者设置,带有BlockingCollection
。您可以使生产者和消费者线程更干净:
private static void ProcessThread1()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Adding data..");
_samples.TryAdd(i, Timeout.Infinite, _cancellationTokenSource.Token);
// not sure why the sleep is here
Thread.Sleep(1000);
}
// Marks the queue as complete for adding.
// When the queue goes empty, the consumer will know that
// no more data is forthcoming.
_samples.CompleteAdding();
}
private static void ProcessThread2()
{
int data;
while (_samples.TryTake(out data, TimeSpan.Infinite, _cancellationTokenSource.Token))
{
// Do some work.
Console.WriteLine("Processing data..");
}
Console.WriteLine("Cancelled.");
}
private static void ProcessThread1()
{
对于(int i=0;i<10;i++)
{
Console.WriteLine(“添加数据…”);
_TryAdd(i,Timeout.Infinite,_cancellationTokenSource.Token);
//不知道为什么这里有睡眠
睡眠(1000);
}
//将队列标记为完成添加。
//当队列变空时,消费者将知道
//没有更多的数据。
_samples.CompleteAdding();
}
私有静态void ProcessThread2()
{
int数据;
while(_samples.TryTake(out data,TimeSpan.Infinite,_cancellationTokenSource.Token))
{
//做一些工作。
Console.WriteLine(“处理数据…”);
}
控制台。写入线(“取消”);
}
您仍然需要该输入线程(除非您希望在Console.KeyAvailable
上旋转一个循环),但这大大简化了您的生产者和消费者。什么版本的.NET?我使用了.NET async,并按照Jim提到的优化了它们。尽管我在这里给出了控制台的示例,但我必须在WPF应用程序中执行此操作,我正在努力将其移动。谢谢你和吉姆的快速回复。