c#高效的线程安全队列ConcurrentQueue的实现

实现线程安全队列的方式很多,而ConcurrentQueue是.NET Framework提供的线程安全的队列实现,同时是高效的,下面详细讲解一下如何使用和实现ConcurrentQueue。

ConcurrentQueue是什么?

ConcurrentQueue是.NET Framework提供的线程安全的队列实现,支持多线程并发操作。它实现了IProducerConsumerCollection和IEnumerable接口,并且提供了一些特殊的方法和属性,例如Enqueue、TryDequeue等。

使用ConcurrentQueue

使用ConcurrentQueue很简单,只需要引入System.Collections.Concurrent命名空间,然后实例化一个ConcurrentQueue对象即可。下面是一个示例:

using System.Collections.Concurrent;

...

ConcurrentQueue<int> queue = new ConcurrentQueue<int>();

在上面的示例中,实例化了一个ConcurrentQueue对象,它可以存放int类型的数据。接下来,我们可以使用Enqueue、TryDequeue等方法操作队列。

下面是一些常用的方法和属性:

  • Enqueue(T item):将一个元素添加到队列末尾。

  • TryDequeue(out T result):尝试从队列头部取出一个元素,并将其赋值给result,返回是否取出成功的bool值。

  • Count:获取队列中元素的数量。

实现ConcurrentQueue

对于ConcurrentQueue的实现,简单来说,就是利用了非阻塞的无锁算法 CAS(Compare-And-Swap,比较并替换)来实现。

CAS算法是一种基于硬件实现的原子操作,它提供了一种线程安全的方式来更新共享的变量。当多个线程同时尝试更新同一个变量时,只有一个线程能够成功,而其他的线程则需要重新尝试,直到更新成功为止。

ConcurrentQueue的具体实现过程,可以参考下面的示例:

public class ConcurrentQueue<T>
{
    private volatile Node<T> _head;
    private volatile Node<T> _tail;

    public ConcurrentQueue()
    {
        _head = _tail = new Node<T>(default(T)); // 创建一个空节点
    }

    public void Enqueue(T item)
    {
        var newNode = new Node<T>(item);

        while (true)
        {
            var tail = _tail;
            var next = tail.Next;

            if (tail == _tail)
            {
                if (next == null)
                {
                    if (Interlocked.CompareExchange(ref tail.Next, newNode, null) == null)
                    {
                        Interlocked.CompareExchange(ref _tail, newNode, tail);
                        return; // 成功插入节点
                    }
                }
                else
                {
                    Interlocked.CompareExchange(ref _tail, next, tail);
                }
            }
        }
    }

    public bool TryDequeue(out T result)
    {
        while (true)
        {
            var head = _head;
            var tail = _tail;
            var next = head.Next;

            if (head == _head)
            {
                if (head == tail)
                {
                    if (next == null)
                    {
                        result = default(T); // 队列为空
                        return false;
                    }
                    Interlocked.CompareExchange(ref _tail, next, tail);
                }
                else
                {
                    result = next.Value;
                    if (Interlocked.CompareExchange(ref _head, next, head) == head)
                    {
                        return true;
                    }
                }
            }
        }
    }

    private class Node<T>
    {
        public readonly T Value;
        public volatile Node<T> Next;

        public Node(T value)
        {
            Value = value;
        }
    }
}

在上面的示例中,我们实现了Enqueue和TryDequeue方法,利用CAS算法实现了线程安全的入队和出队操作。

具体实现过程如下:

  • Enqueue:在尾节点后面插入一个新节点,如果在插入之前尾节点发生了变化,则需要重新获取尾节点,直到插入成功为止。

  • TryDequeue:获取头节点和尾节点,获取头节点的下一个节点,通过CAS算法进行头节点的更新,如果更新成功,则返回被删元素的值;否则,重新开始循环。如果队列为空,则返回默认值。

综上,通过ConcurrentQueue的实现,我们可以实现线程安全的队列操作。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:c#高效的线程安全队列ConcurrentQueue的实现 - Python技术站

(0)
上一篇 2023年6月6日
下一篇 2023年6月6日

相关文章

  • CommunityToolkit.Mvvm8.1 消息通知(4)

    本系列文章导航 https://www.cnblogs.com/aierong/p/17300066.html https://github.com/aierong/WpfDemo (自我Demo地址)   希望提到的知识对您有所提示,同时欢迎交流和指正 作者:aierong出处:https://www.cnblogs.com/aierong   说明 为了…

    C# 2023年4月22日
    00
  • 使用Npoi操作excel的解决办法

    当你需要使用C#来操作excel时,Npoi是一个非常好用的库。本文将详细讲解如何使用Npoi操作excel的解决办法,包含Excel的读取和保存。 1. 添加Npoi依赖 首先需要在Visual Studio中添加Npoi的依赖。可以使用NuGet来添加依赖,搜索Npoi并进行安装。 2. 读取Excel 接下来,我们将讲解如何使用Npoi来读取Excel…

    C# 2023年5月15日
    00
  • c# Winform同一数据源多个控件保持同步

    下面我将为您详细讲解“C# Winform同一数据源多个控件保持同步”的攻略。 1. 前言 在使用C# Winform进行开发时,我们经常会遇到这样的需求:多个控件需要绑定同一个数据源,并且需要保持同步。例如,我们要在一个表格控件和一个文本框控件中显示同一个数据集的内容,并且需要在其中任意一个控件上进行修改后,同步更新到数据源和其他控件上。这时候,我们就需要…

    C# 2023年6月1日
    00
  • C# Lambda 知识回顾

    C# Lambda 知识回顾 什么是Lambda表达式 Lambda表达式是C# 3.0中引入的一个新特性,它可以使我们更简洁的书写代码。Lambda表达式本质上是一个匿名方法,它可以被用来创建委托或表达式树。Lambda表达式对于编写LINQ查询表达式或事件处理程序代码非常有用。 Lambda表达式的语法如下: (parameter_list) =>…

    C# 2023年6月6日
    00
  • C#实现发送手机验证码功能

    一、生成验证码 使用Random类生成随机数字或字母,示例代码如下: Random random = new Random(); string code = ""; for (int i = 0; i < 6; i++) { code += random.Next(10); } 将随机生成的验证码保存到Session中,代码如下: …

    C# 2023年6月6日
    00
  • Unity游戏开发实现背包系统的示例详解

    我来为你详细讲解“Unity游戏开发实现背包系统的示例详解”的完整攻略。 背包系统的概述 在游戏开发中,背包系统是一个比较常见的功能。它通常用于存储玩家各类物品,如道具、装备等。在 Unity 游戏开发中,实现背包系统有很多不同的方法,但其中比较常见的方法是往场景中添加一个 Panel,通过控制 Panel 中的 UI 元素来实现。 实现背包系统的步骤 实现…

    C# 2023年6月3日
    00
  • C#中Stopwatch的使用及说明

    C#中Stopwatch的使用及说明 什么是Stopwatch Stopwatch是C#中用来计算代码块执行时间的类。它通过记录时间戳(以当前系统时钟为基础),来计算代码块执行所需的时间。 导入Stopwatch命名空间 在使用Stopwatch类之前,需要导入System.Diagnostics命名空间,这可以通过在代码开头添加以下语句来实现: using…

    C# 2023年6月1日
    00
  • C#自定义签名章实现方法

    C#自定义签名章实现方法 在C#中,自定义签名章可以用于电子文档的签名或者证明身份等,下面将讲解如何实现C#自定义签名章。 步骤一:创建嵌入资源文件夹 首先需要创建一个嵌入资源文件夹,用于存放自定义签名章的相关图片和字体文件等。创建方式如下: 右键点击项目名称,选择“添加” > “新建文件夹”; 输入文件夹名称,例如“Resources”; 右键点击新…

    C# 2023年6月3日
    00
合作推广
合作推广
分享本页
返回顶部