C# 如何使UI线程休眠以赋予它一些任务

C# 如何使UI线程休眠以赋予它一些任务,c#,multithreading,C#,Multithreading,我试图在应用程序启动时启动一个线程,并等待UI在不使用BackgroundWorker的情况下给它一些工作。这个线程在没有工作时休眠,在ui要求它做某事时唤醒 更多详情: 简单的WPF应用程序:我有一个StorageClass将文件复制到长期存储。此类是WPF应用程序的一部分。当用户单击按钮将文件存储到长期存储(低速阵列)时,我需要一个线程将此文件从高速存储阵列复制到长期存储。这些是大文件,我不希望UI被阻止。我想使用一个等待指令传输的线程。希望这能让我更清楚地知道我想做什么 如果您使用的是.N

我试图在应用程序启动时启动一个线程,并等待UI在不使用BackgroundWorker的情况下给它一些工作。这个线程在没有工作时休眠,在ui要求它做某事时唤醒

更多详情:


简单的WPF应用程序:我有一个StorageClass将文件复制到长期存储。此类是WPF应用程序的一部分。当用户单击按钮将文件存储到长期存储(低速阵列)时,我需要一个线程将此文件从高速存储阵列复制到长期存储。这些是大文件,我不希望UI被阻止。我想使用一个等待指令传输的线程。希望这能让我更清楚地知道我想做什么

如果您使用的是.NET 4.0或更高版本,我建议直接使用TPL over threading,我建议使用
BlockingCollection
,作为UI可以通过该集合为消费者“提供一些工作”的一种方式

然后,消费者可以是一个长期运行的
任务
(同样来自TPL),它从
BlockingCollection
中消费,这样,您就不需要任何睡眠或类似的手动工件,
BlockingCollection
允许您在给定的时间段内进行阻塞,然后在物品准备好消费后恢复

因此,您可以将取消令牌源、阻塞集合和任务定义为:

    private BlockingCollection<Transaction> _bin = new BlockingCollection<Transaction>();
    private CancellationTokenSource _tokenSource = new CancellationTokenSource();
    private Task _consumer;
然后,当表单加载时,您可以通过执行以下操作来启动任务:

// when you have a task running for life of your program, make sure you
// use TaskCreationOptions.LongRunning.  This typically sets up its own
// dedicated thread (not pooled) without having to deal with threads directly
_consumer = Task.Factory.StartNew(ConsumeTransactions, _tokenSource.Token, 
                                  TaskCreationOptions.LongRunning, TaskScheduler.Default);
        _bin.TryAdd(someTransaction);
然后通过执行以下操作添加项目:

// when you have a task running for life of your program, make sure you
// use TaskCreationOptions.LongRunning.  This typically sets up its own
// dedicated thread (not pooled) without having to deal with threads directly
_consumer = Task.Factory.StartNew(ConsumeTransactions, _tokenSource.Token, 
                                  TaskCreationOptions.LongRunning, TaskScheduler.Default);
        _bin.TryAdd(someTransaction);
其中,
事务
就是您定义要执行的工作单元的内容

最后,当您的应用程序要关闭时,它可以执行以下操作:

_bin.CompleteAdding();
它告诉消费者不再向队列中添加更多的项目,这将使
TryTake()
返回
false
,并退出循环,因为
\u bin.IsCompleted
将成为
true


然后,长时间运行的任务可以在阻塞get上循环,直到取消令牌(也是TPL)设置为告诉它关闭…

太模糊了。。。定义“给它一些工作”。。。尽管我强烈怀疑您正在寻找的(如果您在.NET4或更高版本中)是一个
BlockingCollection
。但我还没有做任何事情。只是尝试一下。但我会看看你的评论,詹姆斯。我正在使用.NET 4.0工具,我刚刚添加了一些代码块…启动新线程不会阻止UI线程。为什么不使用
BackgroundWorker
?它正是为了实现这一点而设计的。基于您的jumpt start,我非常激动。值得一提的是,使用
BackgroundWorker
而不是
Tasks
将产生几乎相同的代码。您可以简单地将
ConsumeTransactions
方法作为事件处理程序添加到
DoWork
中,而不是使用
Task.StartNew
在后台开始运行它。@Servy:是的,刚才提到了
Task
,因为我更喜欢服务器。主要的一点是,他可以使用
BlockingCollection
,这样他就不必“旋转”或“睡眠”他的线程/任务,他只需尝试执行其余的任务即可。@JamesMichaelHare我的观点是,这是一种很好的方法,无论您在非UI线程中运行某些代码时使用何种机制,它都会起作用。您可以显式地新建一个线程并启动它,它实际上是相同的。答案比基于
任务的方法更普遍。(这不是一件坏事,这是一件好事。)James和所有如果我使用backgroundworker线程:如果我们在后台工作线程完成第一条指令之前向其传输多条指令,会发生什么?它不会产生多个线程吗?这个想法是我想让它排队等待一个线程来解决它。那么Backgroundworker线程是一个好的选择吗?我正在深入研究James的解决方案,因为我担心在第一个请求完成之前会出现多个请求