没有合适的资源?快使用搜索试试~ 我知道了~
c# 线程安全队列的用法原理及使用示例
16 下载量 55 浏览量
2021-01-21
15:16:26
上传
评论
收藏 131KB PDF 举报
温馨提示
试读
11页
什么是线程安全? 答:线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。 在多线程并行的情况下会出现共享数据会线程间读取与写入不一直的情况,为了解决这种情况,通常会使用锁来解决,也就是将并行改为串行。但是在使用穿行违背了使用多线程并发的初衷,这种情况下我们可以考虑采用线程安全结构。 先看下线程安全队列的用法: ConcurrentQueue<int> ts = new System.Collections.Concurrent.ConcurrentQueue
资源推荐
资源详情
资源评论
c# 线程安全队列的用法原理及使用示例线程安全队列的用法原理及使用示例
什么是线程安全?什么是线程安全?
答:线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代
码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。
在多线程并行的情况下会出现共享数据会线程间读取与写入不一直的情况,为了解决这种情况,通常会使用锁来解决,也就是
将并行改为串行。但是在使用穿行违背了使用多线程并发的初衷,这种情况下我们可以考虑采用线程安全结构。
先看下线程安全队列的用法:
ConcurrentQueue<int> ts = new System.Collections.Concurrent.ConcurrentQueue<int>();
ts.Enqueue(1);
ts.Enqueue(2);
ts.Enqueue(3);
ts.Enqueue(4);
foreach (var r in ts)
{
Console.Write($"data:{r} ");
}
Console.WriteLine();
ts.TryPeek(out int pk);
Console.WriteLine($"peek:{pk}");
ts.TryDequeue(out int ck);
ts.Enqueue(5);
ts.Enqueue(6);
Console.WriteLine();
foreach (var r in ts)
{
Console.Write($"data:{r} ");
}
Console.WriteLine();
Console.ReadLine();
现在我们看下线程安全队列的实现方式:(参考自:.net framework 4.8),核心代码全部做了注释。
总的来说,(总结语放到前面,防止代码篇幅太大,同志们没有耐心翻到最底下~)
1、线程安全队列通过SpinWait自旋类来实现等待并行线程完成与Interlocked原子操作类计数实现的。
2、线程安全队列通过单向链表实现的,链的节点为长度32的数组,通过记录链的头节点与尾节点、以及队列的头尾实现队列
的存储与入队、出队操作的。
public class MyConcurrentQueue<T> : IProducerConsumerCollection<T>
{
[NonSerialized] private volatile Segment m_head;
[NonSerialized] private volatile Segment m_tail;
private T[] m_serializationArray;
private const int SEGMENT_SIZE = 32;
[NonSerialized] internal volatile int m_numSnapshotTakers = 0;
/// <summary>
/// 链尾部节点
/// </summary>
public MyConcurrentQueue()
{
m_head = m_tail = new Segment(0, this);
}
//尝试添加
bool IProducerConsumerCollection<T>.TryAdd(T item)
{
Enqueue(item);
return true;
}
/// <summary>
/// 尝试从中移除并返回对象
/// </summary>
/// <param name="item">
/// </remarks>
bool IProducerConsumerCollection<T>.TryTake(out T item)
{
return TryDequeue(out item);
}
/// <summary>
/// 判断当前链是否为空
/// </summary>
public bool IsEmpty
{
get
{
Segment head = m_head;
if (!head.IsEmpty)
//如果头不为空,则链非空
return false;
else if (head.Next == null)
//如果头节点的下一个节点为空,且为链尾,
return true;
else
//如果头节点为空且不是最后一个节点 ,则标识另一个线程正在写入该数组
//等待中..
{
SpinWait spin = new SpinWait();
while (head.IsEmpty)
{
//此时为空
if (head.Next == null)
return true;
//否则标识正在有线程占用写入
//线程循环一次
spin.SpinOnce();
head = m_head;
}
return false;
}
}
}
/// <summary>
/// 用来判断链是否在变化
/// </summary>
/// <param name="head"></param>
/// <param name="tail"></param>
/// <param name="headLow"></param>
/// <param name="tailHigh"></param>
private void GetHeadTailPositions(out Segment head, out Segment tail,
out int headLow, out int tailHigh)
{
head = m_head;
tail = m_tail;
headLow = head.Low;
tailHigh = tail.High;
SpinWait spin = new SpinWait();
Console.WriteLine($"head.Low:{head.Low},tail.High:{tail.High},head.m_index:{head.m_index},tail.m_index:
{tail.m_index}");
//通过循环来保证值不再更改(也就是说并行线程操作结束)
//保证线程串行核心的判断逻辑
while (
//头尾发生变化
head != m_head || tail != m_tail
//如果队列头、尾索引发生变化
|| headLow != head.Low || tailHigh != tail.High
|| head.m_index > tail.m_index)
{
spin.SpinOnce();
head = m_head;
tail = m_tail;
headLow = head.Low;
tailHigh = tail.High;
}
}
/// <summary>
/// 获取总数
/// </summary>
public int Count
{
get
{
Segment head, tail;
int headLow, tailHigh;
GetHeadTailPositions(out head, out tail, out headLow, out tailHigh);
if (head == tail)
{
return tailHigh - headLow + 1;
}
剩余10页未读,继续阅读
资源评论
weixin_38607864
- 粉丝: 3
- 资源: 934
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功