首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >BlockingCollection线程安全吗?

BlockingCollection线程安全吗?
EN

Stack Overflow用户
提问于 2020-01-14 07:01:18
回答 3查看 1.5K关注 0票数 2
代码语言:javascript
复制
BlockingCollection<int> blockingCollection = new BlockingCollection<int>();
    // create and start a producer
    Task.Factory.StartNew(() => {
        // put items into the collectioon
        for (int i = 0; i < 1000; i++)
        {
            blockingCollection.Add(i);
        }
        // mark the collection as complete
        blockingCollection.CompleteAdding();
    });
    // create and start a producer
    Task.Factory.StartNew(() => {
        while (!blockingCollection.IsCompleted)
        {
            // take an item from the collection
            int item = blockingCollection.Take();
            // print out the item
            Console.WriteLine("Taskid{1} Item {0}", item, Task.CurrentId);
        }
    });

    // create and start a producer
    Task.Factory.StartNew(() => {
        while (!blockingCollection.IsCompleted)   // if the blockingCollection is not completed
        {
            // take an item from the collection
            int item = blockingCollection.Take();  // but in here, all the items have been taken by other thread, this line will wait forever?
            // print out the item
            Console.WriteLine("Taskid{1} Item {0}", item,Task.CurrentId);
        }
    });
    Console.ReadLine();

关键代码行:

代码语言:javascript
复制
    while (!blockingCollection.IsCompleted)   // if the blockingCollection is not completed
    int item = blockingCollection.Take();  // but in here, all the items have been taken by other thread, this line will wait forever?
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-01-14 07:07:21

问题1-线程安全吗?

引用BlockingCollection文档

为实现线程安全的集合提供阻塞和绑定功能。

问题2-- Take()会永远用吗?

来自正式文档:MS关于阻塞收集-获取

OperationCanceledException BlockingCollection是空的,并已被标记为完整的添加。

因此,当在已完成的Take上调用BlockingCollection时,将引发异常,您可以相应地处理该异常。

票数 1
EN

Stack Overflow用户

发布于 2020-01-14 07:18:07

没错,BlockingCollection<T>是线程安全的。

为了避免IsCompleted检查,可以在GetConsumingEnumerable()的帮助下放置相同的逻辑,直到阻塞集合完成为止:

代码语言:javascript
复制
  // Producer:

  Task.Run(() => { 
    for (int i = 0; i < 1000; i++)
      blockingCollection.Add(i);

    blockingCollection.CompleteAdding();
  });    

  // Consumers:

  Task.Run(() => {
    foreach (var item in blockingCollection.GetConsumingEnumerable()) 
      Console.WriteLine("Taskid{1} Item {0}", item, Task.CurrentId);
  });

  Task.Run(() => {
    foreach (var item in blockingCollection.GetConsumingEnumerable()) 
      Console.WriteLine("Taskid{1} Item {0}", item, Task.CurrentId);
  });
票数 4
EN

Stack Overflow用户

发布于 2020-01-14 07:40:35

BlockingCollection类是线程安全的,因为当多个线程并发调用时,它的内部状态是不受损坏的。从某种意义上说,它的存在并不是线程安全的,因为它的存在与线程安全有关--线程不安全的代码块!

您的代码是不安全的,因为在调用IsCompletedTake之间,另一个线程可以调用Complete方法,并将BlockingCollection的状态从未完成更改为已完成。线程安全解决方案是在原子操作中使用将IsCompletedTake结合在一起的API。BlockingCollection类中没有这样的API,但是您可以使用GetConsumingEnumerable方法实现您想要的结果。此方法返回一个在等待可用项时阻塞的IEnumerable,并在BlockingCollection完成时完成。实际上,这是使用此集合的标准和首选方法。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59728872

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档