C#队列的线程安全问题
在上一篇博客https://zhuanlan.zhihu.com/p/412083493里提到了用队列这种数据结构来存储串口数据的方法,看评论里有提到我的队列没有加锁,线程不安全,仔细研究了下,确实不安全,这里感谢大佬提醒。
队列是其元素以**先进先出(FIFO)**的方式来处理集合,先入队的元素会先读取。
队列在现实生活中的例子数不胜数。例如:排队打饭,排队购买机票,打印队列中等待处理的打印业务等
解决方法:
使用ConcurrentQueue类来代替Queue类。
测试代码:
这里分别定义了一个ConcurrentQueue类和Queue类来进行测试。
一个线程Enqueue 10000个数据的,另一个Dequeue 5000个数,如果线程安全,最后应该还有5000个数
代码如下:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StackQueue
{
class Program
{
public static Queue<Product> productQueue = new Queue<Product>(50000);//定义一个队列-----存在并发风险
public static ConcurrentQueue<Product> productCQ = new ConcurrentQueue<Product>();//无需考虑并发
static void Main(string[] args)
{
//普通入队操作 存在并发风险
Task t1 = new TaskFactory().StartNew(RuDui);
//普通出队操作 存在并发风险
Task t2 = new Task(() => ChuDui());
t2.Start();
Task.WaitAll(t1, t2);
Console.WriteLine("productQueue队列中共有元素:" + productQueue.Count + "个。实际应该有5000个");
//安全入队操作 存在并发风险
Task t3 = new TaskFactory().StartNew(RuDuiCC);
//安全出队操作 存在并发风险
Task t4 = new Task(() => ChuDuiCC());
t4.Start();
Task.WaitAll(t3, t4);
Console.WriteLine("productCQ队列中共有元素:" + productCQ.Count + "个。实际应该有5000个");
Console.ReadKey();
}
public static void RuDui() //定义一个入队方法 先进先出(不安全)
{
for (int i = 1; i < 10001; i++)
{
Product model = new Product() { Name = "商品" + i, Category = "水果", SellPrice = 10 };
productQueue.Enqueue(model);
}
}
public static void ChuDui()//定义一个出队方法 先进先出(不安全)
{
for (int i = 1; i < 5001; i++)
{
while (productQueue.Count < 1) ;
productQueue.Dequeue();
}
}
public static void RuDuiCC() //保证线程安全的入队方法
{
for (int i = 1; i < 10001; i++)
{
Product model = new Product() { Name = "商品" + i, Category = "水果", SellPrice = 10 };
productCQ.Enqueue(model);
}
}
public static void ChuDuiCC() //保证线程安全的出队方法
{
Product re;
for (int i = 1; i < 5001; i++)
{
while (productCQ.Count < 1) ;
productCQ.TryDequeue(out re);
}
}
}
public class Product
{
public string Name { get; set; }
public string Category { get; set; }
public int SellPrice { get; set; }
}
}