如何为UI创建一个线程睡眠以给它一些任务

时间:2012-07-25 15:59:08

标签: c# multithreading

我正在尝试在应用程序启动时启动一个线程,并等待UI在不使用BackgroundWorker的情况下为其提供一些工作。当没有给出任何工作时,该线程会休眠,当ui要求它执行某些操作时,该线程会被唤醒。

更多详情:

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

1 个答案:

答案 0 :(得分:2)

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

然后,消费者可以是从Task消耗的长期BlockingCollection<T>(再次来自TPL),这样,您就不需要任何睡眠或手动工件,BlockingCollection<T>允许您阻止等待一段时间,然后在项目准备好消耗后恢复。

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

    private BlockingCollection<Transaction> _bin = new BlockingCollection<Transaction>();
    private CancellationTokenSource _tokenSource = new CancellationTokenSource();
    private Task _consumer;

您的消费者方法可以定义为:

    private void ConsumeTransactions()
    {
        // loop until consumer marked completed, or cancellation token set
        while (!_bin.IsCompleted && !_tokenSource.Token.IsCancelRequested)
        {
            Transaction item;

            // try to take item for 100 ms, or until cancelled 
            if (_bin.TryTake(out item, 100, _tokenSource.Token)
            {
                // consume the item
            }
        }
    }

然后,您可以在表单加载时启动任务:

// 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);

Transaction只是您定义要执行的工作单元的任何内容......

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

_bin.CompleteAdding();

告诉消费者不再有任何项目添加到队列中,这将使TryTake()返回false,并退出循环,因为_bin.IsCompletedtrue 1}}。

您的长时间运行任务可以循环阻塞获取,直到取消令牌(也是TPL)设置为告诉它关闭...