C# 阻止收集多个消费者
我有以下代码,其中包含一个生产者线程和多个消费者线程。您知道多个使用者是否是线程安全的吗。例如,线程1是否有可能正在消费,而线程2是否并行消费并更改线程1中使用的项目的值C# 阻止收集多个消费者,c#,multithreading,thread-safety,consumer,blockingcollection,C#,Multithreading,Thread Safety,Consumer,Blockingcollection,我有以下代码,其中包含一个生产者线程和多个消费者线程。您知道多个使用者是否是线程安全的吗。例如,线程1是否有可能正在消费,而线程2是否并行消费并更改线程1中使用的项目的值 namespace BlockingColl { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object se
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; }
}
}
namespace BlockingColl
{
公共部分类Form1:Form
{
公共表格1()
{
初始化组件();
}
私有无效按钮1\u单击(对象发送者,事件参数e)
{
尝试
{
对于(int i=0;i<3;i++)
{
ThreadPool.QueueUserWorkItem((x)=>
{
foreach(bc.GetConsumingEnumerable()中的变量项)
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId+“-”+item+“-”+DateTime.Now.ToString(“MM/dd/yyyy hh:MM:ss.fff tt”);
}
});
}
}
捕获(例外)
{
投掷;
}
}
私有无效按钮2\u单击(对象发送者,事件参数e)
{
对于(int i=0;i<3;i++)
{
ThreadPool.QueueUserWorkItem((x)=>
{
Cache.Consume();
});
}
对于(int i=0;i<50000;i++)
{
Cache.bc.TryAdd(新客户端(){ClientId=i,ClientName=“Name”+i});
}
}
}
静态类缓存
{
public static BlockingCollection bc=new BlockingCollection();
公共静态void消费()
{
foreach(bc.GetConsumingEnumerable()中的变量项)
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId+“-”+item+“-”+DateTime.Now.ToString(“MM/dd/yyyy hh:MM:ss.fff tt”);
}
}
}
公共类客户端
{
public int ClientId{get;set;}
公共字符串ClientName{get;set;}
}
}
提前感谢阻止收藏仅阻止收藏本身。不是列表中的对象。一旦您使用了元素,它将从集合中删除,因此其他线程将无法访问它(至少通过集合)
那个缓存在我看来更像一个缓冲区。它在阻塞集合之上添加了什么?很奇怪,缓存能够使用自己的元素。谢谢。你是对的。它是一个缓冲区。这些名字无关紧要。我想问的场景是,当线程1正在消费时,线程2是否有可能并行消费并更改线程1中使用的项目的值,因为正如您所看到的,我并行调用了消费者三次(Button1_Click事件),然后回答是否,没有机会,但是因为不同的线程不能使用相同的元素。您是否需要不同的线程来访问集合中的所有元素?如果是这种情况,则不能使用GetConsumingEnumerable()方法。否。我想让多个消费者尽快使用缓冲区。因此,线程2不会修改在线程1上的foreach循环中对“item”对象执行的任何操作?因为正如您所看到的,Consume方法是静态的。它不会被修改,因为如果consuming enumerable已经为线程2返回了它,它将不会为线程1返回它。每个线程都会得到一些项目,但不会有重叠。看来你是对的。每个线程都在访问自己的项“实例”