2012-03-01 115 views
3

我想实现一个单生产者和多个消费者模式的多文件下载。多线程单生产者多消费者实现

我有什么: - 当一个新的链接被发现 - - 它发现新链接的循环 要下载的代码调用下载功能 - 下载函数接受源文件路径和目标文件路径和下载文件。

我想做什么 - 我想同时下载文件的X号(我不知道文件的总数) - 在任何时候,我应该能够同时下载X文件 - 只要的1 X文件下载完毕 - 调用函数应该能够添加新的下载马上 - 这反过来下载马上

  • 所以我有一个生产函数,不断添加新的下载队列(在任何时候最大X下载)
  • 多个X线程消耗下载并开始单独下载。一旦它完成下载 - 制作人应该能够添加新的下载 - 这将产生新的线程。

实例将非常感激

回答

2

ReaderWriterLockSlim class旨在做到这一点。

此外,检查该网站的辉煌约线程:

http://www.albahari.com/threading/part4.aspx#_Reader_Writer_Locks

的例子来自上面的网站。

class SlimDemo 
{ 
    static ReaderWriterLockSlim _rw = new ReaderWriterLockSlim(); 
    static List<int> _items = new List<int>(); 
    static Random _rand = new Random(); 

    static void Main() 
    { 
    new Thread (Read).Start(); 
    new Thread (Read).Start(); 
    new Thread (Read).Start(); 

    new Thread (Write).Start ("A"); 
    new Thread (Write).Start ("B"); 
    } 

    static void Read() 
    { 
    while (true) 
    { 
     _rw.EnterReadLock(); 
     foreach (int i in _items) Thread.Sleep (10); 
     _rw.ExitReadLock(); 
    } 
    } 

    static void Write (object threadID) 
    { 
    while (true) 
    { 
     int newNumber = GetRandNum (100); 
     _rw.EnterWriteLock(); 
     _items.Add (newNumber); 
     _rw.ExitWriteLock(); 
     Console.WriteLine ("Thread " + threadID + " added " + newNumber); 
     Thread.Sleep (100); 
    } 
    } 

    static int GetRandNum (int max) { lock (_rand) return _rand.Next(max); } 
} 
+0

生产者=作家,消费者=读者。 Reader/Writer是读取或写入共享数据的代理程序的线程术语中的常用名称(示例中下载队列= _items)。 – 2012-03-01 09:17:56

+1

如何在_items列表中的Read()方法中处理后删除线程安全的项目? – Odrai 2014-04-04 13:07:04

0

我会建议寻找到Task Parallel Library。这非常干净地包装了方法调用,并为您管理多个线程。

+0

你确定任务并行库解决访问共享数据的问题吗?在这里查看http://msdn.microsoft.com/en-us/library/dd997392.aspx'避免写入共享内存位置'部分。 – 2012-03-01 06:53:42

0

使用并行收集来进行老板和其工作人员之间的沟通。
ConcurrentQueue(如果您关心订单)或ConcurrentBag。
老板添加到ConcurrentQueue(添加方法)和船员从队列中取(Take方法)。让我知道你是否需要代码。

4

对于此P/C问题,您只需要一个BlockingCollection<T>即可。

//shared and thread-safe 
static BlockingCollection<string> queue = new BlockingCollection<string>(100); 

// Producer 
queue.Add(fileName); // will block when full 

// Consumer 
if (queue.TryTake(out fileName, timeOut)) // waits when empty 
    ... 

您将需要使用超时和CancellationTokens稍微调整它。

+0

在您退出某个项目后,执行一些处理后,如何将结果返回给调用进程? – gdp 2013-03-26 17:36:05

+0

'调用过程'究竟是什么? – 2013-03-26 17:59:20

+0

我正在实施一个队列来限制Web请求。所以我有一个方法让我们从webservice中说出DownloadUser(),并将请求添加到队列中以进行限制。我怎样才能将结果返回给该方法DownloadUser()? – gdp 2013-03-26 18:07:08