0

我正在尝试在应用程序启动时启动一个线程并等待 UI 在不使用 BackgroundWorker 的情况下为其提供一些工作。这个线程在没有工作时休眠,当用户界面要求它做某事时唤醒。

更多细节:

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

4

1 回答 1

2

如果您使用的是 .NET 4.0 或更高版本,我建议直接使用 TPL 而不是线程,并且我建议使用 aBlockingCollection<T>作为 UI 可以通过集合“提供一些工作”供消费者执行的方式。

然后,消费者可以是一个长期运行的Task(同样来自 TPL),BlockingCollection<T>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()return false,并退出循环,因为那时_bin.IsCompleted将是true

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

于 2012-07-25T16:09:28.573 回答