多线程BlockingCollection的值相同

时间:2014-04-03 12:43:02

标签: c# multithreading blockingcollection

我在C#应用程序中使用两个线程来访问相同的BlockingCollection。这工作正常,但我想要检索第一个值两次,以便两个线程检索相同的值*。

几秒钟后,我想轮询两个线程的currentIndex并删除每个值<指数。因此,例如,线程的最低currentIndex是5,应用程序删除队列中索引0 -5处的项目。另一种解决方案是,如果所有线程都处理了值,则删除队列中的值。

我怎样才能做到这一点?我想我需要另一种缓冲区..?

提前谢谢!

*如果thread1调用了.Take(),则该集合中的项目将被删除,而thread2无法再次获得相同的项目。


更新

我想将数据存储在缓冲区中,因此例如thread1将数据保存到HDD,而thread2分析(相同)数据(并发)。

2 个答案:

答案 0 :(得分:5)

使用producer-consumer将Value1添加到两个单独的ConcurrentQueues中。让线程出列然后从它们自己的队列中处理它们。

编辑7/4/14: 这是一个朦胧,hacky,半思考的解决方案:创建一个缓冲的自定义对象。它可以包含您尝试在线程1中缓冲的信息和线程2中的分析结果的空间。

将对象添加到线程1和BlockingCollection中的缓冲区。使用线程2分析结果并使用结果更新对象。阻止集合不应该太大,因为它只处理引用不应该打击你的记忆。这假设您不会在两个线程上同时修改缓冲区中的信息。

另一个也是一半经过深思熟虑的解决方案是同时将信息提供给缓冲区和阻塞集合。分析来自BlockingCollection的数据,将其提供给输出集合并再次与缓冲区匹配。如果你做得对,这个选项可以处理并发修改,但可能更多的工作。

我认为选项一更好。正如我已经指出的那样,它们只有一半形成,但它们可能会帮助您找到适合您特定需求的东西。祝你好运。

答案 1 :(得分:1)

我建议重新考虑你的设计。

当你有一个必须处理的项目列表时,给每个线程一个他必须处理的项目队列。

使用这样的解决方案,为两个或多个线程提供相同的值来处理是不成问题的。

像这样的东西,没有经过测试只是打字。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;

namespace ConsoleApplication2
{

  class Item
  {
    private int _value;
    public int Value
    {
      get
      {
        return _value;
      }
    }

    // all you need
    public Item(int i)
    {
      _value = i;
    }
  }

  class WorkerParameters
  {
    public ConcurrentQueue<Item> Items = new ConcurrentQueue<Item>();
  }

  class Worker
  {
    private Thread _thread;
    private WorkerParameters _params = new WorkerParameters();

    public void EnqueueItem(Item item)
    {
      _params.Items.Enqueue(item);
    }

    public void Start()
    {
      _thread = new Thread(new ParameterizedThreadStart(ThreadProc));
      _thread.Start();
    }

    public void Stop()
    {
      // build somthing to stop your thread
    }

    public static void ThreadProc(object threadParams)
    {
      WorkerParameters p = (WorkerParameters)threadParams;
      while (true)
      {
        while (p.Items.Count > 0)
        {
          Item item = null;
          p.Items.TryDequeue(out item);

          if (item != null)
          {
            // do something
          }

        }
        System.Threading.Thread.Sleep(50);
      }
    }
  }

  class Program
  {
    static void Main(string[] args)
    {

      Worker w1 = new Worker();
      Worker w2 = new Worker();
      w1.Start();
      w2.Start();

      List<Item> itemsToProcess = new List<Item>();
      for (int i = 1; i < 1000; i++)
      {
        itemsToProcess.Add(new Item(i));
      }

      for (int i = 1; i < 1000; i++)
      {
        w1.EnqueueItem(itemsToProcess[i]);
        w2.EnqueueItem(itemsToProcess[i]);
      }


    }
  }
}