BlockingCollection多个消费者

7

我有以下代码,其中包括一个生产者线程和多个消费者线程。您是否知道多个消费者是否是线程安全的?例如,线程1正在使用某个项目时,是否有可能并行运行线程2并更改该项目的值?

namespace BlockingColl
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            for (int i = 0; i < 3; i++)
            {

                ThreadPool.QueueUserWorkItem((x) =>
                   {
                       foreach (var item in bc.GetConsumingEnumerable())
                       {
                           Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + item + " - " + DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss.fff tt"));
                       }
                   });
            }
        }
        catch (Exception)
        {

            throw;
        }
    }

    private void button2_Click(object sender, EventArgs e)
    {
        for (int i = 0; i < 3; i++)
        {

            ThreadPool.QueueUserWorkItem((x) =>
               {
                   Cache.Consume();
               });
        }


        for (int i = 0; i < 50000; i++)
        {
            Cache.bc.TryAdd(new Client() { ClientId = i, ClientName = "Name" + i });
        }
    }
}

static class Cache
{
    public static BlockingCollection<Client> bc = new BlockingCollection<Client>();


    public static void Consume()
    {
        foreach (var item in bc.GetConsumingEnumerable())
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + item + " - " + DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss.fff tt"));
        }
    }
}

public class Client
{
    public int ClientId { get; set; }
    public string ClientName { get; set; }
}
}

感谢您的提前帮助。
2个回答

1

一旦您使用了一个元素,它就会从集合中删除,因此其他线程将无法通过该集合访问它(至少是这样)。

那个缓存对我来说更像是一个缓冲区。无论如何,它在阻塞集合之上添加了什么?很奇怪缓存能够消耗自己的元素。


谢谢。你说得对。这是一个缓冲区。名称不重要。我想问的场景是,当线程1正在消耗并且同时线程2在并行消耗时,是否有任何机会更改线程1中使用的项目的值,因为正如你所看到的,我在并行调用消费者三次(Button1_Click事件)。 - pantonis
那么答案是否定的,没有机会,因为不同的线程不能消耗相同的元素。如果您需要不同的线程访问集合中的所有元素,那么您不能使用GetConsumingEnumerable()方法。 - fsimonazzi
不,我的意思是要有多个消费者尽快地消耗缓冲区。因此,在线程1上的foreach循环中对“item”对象进行的任何操作都不会被线程2修改?因为正如您所看到的,Consume方法是静态的。 - pantonis
如果已经为线程2返回,则由于消耗枚举不会为线程1返回,因此它不会被修改。每个线程将获取一些项目,但不会有重叠。 - fsimonazzi
看起来你是对的。每个线程都在访问它自己的“实例”项。 - pantonis
不完全正确。每个线程获取不同的元素子集。 - fsimonazzi

0

BlockingCollection 仅阻止集合本身,而不是列表中的对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接