如何确定我的制作人消费者何时完成它的工作

时间:2014-08-30 06:57:16

标签: c# .net multithreading producer-consumer

我有一个问题我正在尝试决定如何处理和解决它,我有一个应用程序,用户选择某些文件,并且需要将文件添加到我的ListView 但在我需要检查这些文件之前(通过另一个类),我的问题是要知道这个操作完成以便更新我的GUI

请看这堂课:

public class ProducerConsumer : IDisposable
{
    public delegate void OnFileAddDelegate(string file);
    public event OnFileAddDelegate OnFileAddEventHandler;
    BlockingCollection<string> _taskQ = new BlockingCollection<string>();
    public ProducerConsumer(int workerCount)
    {
        // Create and start a separate Task for each consumer:
        for (int i = 0; i < workerCount; i++)
            Task.Factory.StartNew(Consumer);
    }

    public void Dispose()
    {
        _taskQ.CompleteAdding();
    }

    public void Enqueue(string action)
    {
        _taskQ.Add(action);
    }

    private void Consumer()
    {
        // This sequence that we’re enumerating will block when no elements
        // are available and will end when CompleteAdding is called. 
        FileChecker fileChecker = new FileChecker();
        foreach (string item in _taskQ.GetConsumingEnumerable())
        {
            string file = item;
            string result = fileChecker.Check(file);
            if (result != null && OnFileAddEventHandler != null)
                OnFileAddEventHandler(result);
        }
    }
}

我在Winforms应用程序中使用此类,在用户选择需要添加到我的ListView的文件后,此类将此文件(PDF文件)放入Queue并且使用者获取此文件并使用另一个类(FileChecker)检查每个文件(简单搜索),如果文件正常,则向主表单引发Event以添加文件。 现在,当搜索/添加此文件时,我锁定了所有控制器,在此操作结束时,我想要解锁此控制器,但我不知道该类完成它的工作的具体时刻,我尝试放置break-pointConsumer foreach loop的末尾,但它似乎没有到达那里,所以我想知道我怎么知道这个操作何时完成

更新:

这是主要形式:

string[] files // All the files that the user choose

ProducerConsumer producerConsumer = new ProducerConsumer(5);
producerConsumer.OnFileAddEventHandler += pq_OnFileAddEventHandler;
foreach (string item in files)
{
    string filename = item;
    producerConsumer.Enqueue(filename);
}

1 个答案:

答案 0 :(得分:2)

如果你真的想要产生它们并在它们完成时杀死它们,那么 你不应该使用阻塞队列,而是使用同步的正常队列

  1. 填写队列
  2. 产生消费者
  3. 锁定,尝试弹出,解锁消费者
  4. 如果没有任何内容可以退出消费者
  5. 使用原始asnwer表示最后一位消费者完成了它的工作
  6. 完整示例

    public class ProducerConsumer {
        public delegate void FileAddedDelegate(string file);
        public delegate void AllFilesProcessedDelegate();
        public event FileAddedDelegate FileAdded;
        public event AllFilesProcessedDelegate AllFilesProcessed
        readonly Queue<string> queue; int counter;
        public ProducerConsumer(int workerCount, IEnumerable<string> list) {
            queue = new Queue<string>(list); // fill the queue
            counter = queue.Count; // set up counter
        }
        public void Start() {// split this to be able to add event hooks in between
            for (int i = 0; i < workerCount; i++)
                Task.Factory.StartNew(Consumer);
        }
        private void Consumer() {
            FileChecker fileChecker = new FileChecker();
            for(;;) {
                string file;
                lock(queue) { // synchronize on the queue
                    if (queue.Count == 0) return;  // we are done
                    file = queue.Dequeue(); // get file name to process
                } // release the lock to allow other consumers to access the queue
            //  do the job
                string result = fileChecker.Check(file);
                if (result != null && FileAdded != null)
                    FileAdded(result);
            //  decrement the counter
                if(Interlocked.Decremet(counter) != 0)
                    continue; // not the last
            //  all done - we were the last
                if(AllFilesProcessed != null)
                    AllFilesProcessed()
                return;
            }
        }
    }
    

    原始

    注意:您的示例看起来像 idea ,而不是完整的代码。该解决方案专为自由运行的消费者而设计 - 当他们到达空闲队列时,他们正在等待工作和报告。

    使用一些计数器:

    int counter;
    

    在排队文件之前增加它

    Interlocked.Add(ref counter, files.length);
    foreach (string item in files) {
        string filename = item;
        producerConsumer.Enqueue(filename); }
    

    消费者减少和测试:

    if (result != null) {
        if(OnFileAddEventHandler != null)
            OnFileAddEventHandler(result);
        if(Interlocked.Decrement(ref counter) == 0
        && OnAllFilesProcessed != null)
            OnAllFilesProcessed();
    

    链接:System.Threading.Interlocked