使LinkedRingBuffer线程的C#实现安全
我有三个问题:使LinkedRingBuffer线程的C#实现安全,c#,performance,linked-list,thread-safety,buffer,C#,Performance,Linked List,Thread Safety,Buffer,我有三个问题: 你一般认为我解决给定问题的方法如何 您认为我可以进一步提高性能吗 最重要的一点是:如何使我的实现真正线程安全 首先,我所处的简化场景是: 我通过消息系统与不同的设备进行通信。我在很短的时间内收到和发送了成千上万的信息。我在一个多线程环境中,因此许多不同的任务都在发送和等待消息。对于消息接收,事件驱动的方法给我们带来了很多麻烦,使其线程安全。 我有一些接收任务,这些任务从外部获取消息,并且必须将这些消息传递给许多消费者任务 所以我想出了一个不同的方法: 为什么不拥有几千条消息的历史
public class LinkedRingBuffer<T>
{
private LinkedRingBufferNode<T> firstNode;
private LinkedRingBufferNode<T> lastNode;
public LinkedRingBuffer(int capacity)
{
Capacity = capacity;
Count = 0;
}
/// <summary>
/// Maximum count of items inside the buffer
/// </summary>
public int Capacity { get; }
/// <summary>
/// Actual count of items inside the buffer
/// </summary>
public int Count { get; private set; }
/// <summary>
/// Get value of the oldest buffer entry
/// </summary>
/// <returns></returns>
public T GetFirst()
{
return firstNode.Item;
}
/// <summary>
/// Get value of the newest buffer entry
/// </summary>
/// <returns></returns>
public T GetLast()
{
return lastNode.Item;
}
/// <summary>
/// Add item at the end of the buffer.
/// If capacity is reached the link to the oldest item is deleted.
/// </summary>
public void Add(T item)
{
/* create node and set to last one */
var node = new LinkedRingBufferNode<T>(lastNode, item);
lastNode = node;
/* if it is the first node, the created is also the first */
if (firstNode == null)
firstNode = node;
/* check for capacity reach */
Count++;
if(Count > Capacity)
{/* deleted all links to the current first so that its eventually gc collected */
Count = Capacity;
firstNode = firstNode.NextNode;
firstNode.PreviousNode = null;
}
}
/// <summary>
/// Iterate through the buffer from the oldest to the newest item
/// </summary>
public IEnumerable<T> LastToFirst()
{
var current = lastNode;
while(current != null)
{
yield return current.Item;
current = current.PreviousNode;
}
}
/// <summary>
/// Iterate through the buffer from the newest to the oldest item
/// </summary>
public IEnumerable<T> FirstToLast()
{
var current = firstNode;
while (current != null)
{
yield return current.Item;
current = current.NextNode;
}
}
/// <summary>
/// Iterate through the buffer from the oldest to given item.
/// If item doesn't exist it iterates until it reaches the newest
/// </summary>
public IEnumerable<T> LastToReference(T item)
{
var current = lastNode;
while (current != null)
{
yield return current.Item;
if (current.Item.Equals(item))
break;
current = current.PreviousNode;
}
}
/// <summary>
/// Iterate through the buffer from the newest to given item.
/// If item doesn't exist it iterates until it reaches the oldest
/// </summary>
public IEnumerable<T> FirstToReference(T item)
{
var current = firstNode;
while (current != null)
{
yield return current.Item;
if (current.Item.Equals(item))
break;
current = current.PreviousNode;
}
}
/// <summary>
/// Represents a linked node inside the buffer and holds the data
/// </summary>
private class LinkedRingBufferNode<A>
{
public LinkedRingBufferNode(LinkedRingBufferNode<A> previousNode, A item)
{
Item = item;
NextNode = null;
PreviousNode = previousNode;
if(previousNode != null)
previousNode.NextNode = this;
}
internal A Item { get; }
internal LinkedRingBufferNode<A> PreviousNode { get; set; }
internal LinkedRingBufferNode<A> NextNode { get; private set; }
}
}
公共类linkedingbuffer
{
私有linkedingbuffernode firstNode;
私有linkedingbuffernode lastNode;
公共链接DringBuffer(内部容量)
{
容量=容量;
计数=0;
}
///
///缓冲区内项目的最大计数
///
公共整数容量{get;}
///
///缓冲区内项目的实际计数
///
公共整数计数{get;私有集;}
///
///获取最早的缓冲区项的值
///
///
公共T GetFirst()
{
返回firstNode.Item;
}
///
///获取最新缓冲区项的值
///
///
公共T GetLast()
{
返回lastNode.Item;
}
///
///在缓冲区的末尾添加项。
///如果达到容量,则删除指向最旧项目的链接。
///
公共作废新增(T项)
{
/*创建节点并设置为最后一个*/
var node=新的LinkedRingBufferNode(lastNode,item);
lastNode=节点;
/*如果它是第一个节点,则创建的也是第一个节点*/
if(firstNode==null)
第一个节点=节点;
/*检查容量范围*/
计数++;
如果(计数>容量)
{/*删除了指向当前第一个的所有链接,以便最终收集其gc*/
计数=容量;
firstNode=firstNode.NextNode;
firstNode.PreviousNode=null;
}
}
///
///从最早的项到最新的项遍历缓冲区
///
公共IEnumerable LastToFirst()
{
var电流=最后一个节点;
while(当前!=null)
{
收益率返回当前项目;
current=current.PreviousNode;
}
}
///
///从最新项到最旧项遍历缓冲区
///
公共IEnumerable FirstToLast()
{
var电流=第一个节点;
while(当前!=null)
{
收益率返回当前项目;
current=current.NextNode;
}
}
///
///从最早的项到给定项遍历缓冲区。
///如果项目不存在,它将迭代,直到到达最新的项目
///
公共IEnumerable LastToReference(T项)
{
var电流=最后一个节点;
while(当前!=null)
{
收益率返回当前项目;
if(当前项目等于(项目))
打破
current=current.PreviousNode;
}
}
///
///从最新项到给定项迭代缓冲区。
///如果项不存在,它将迭代,直到它到达最早的项
///
公共IEnumerable FirstToReference(T项)
{
var电流=第一个节点;
while(当前!=null)
{
收益率返回当前项目;
if(当前项目等于(项目))
打破
current=current.PreviousNode;
}
}
///
///表示缓冲区内的链接节点并保存数据
///
私有类LinkedRingBufferNode
{
公共LinkedRingBufferNode(LinkedRingBufferNode previousNode,一个项目)
{
项目=项目;
NextNode=null;
PreviousNode=PreviousNode;
if(previousNode!=null)
previousNode.NextNode=此;
}
内部项目{get;}
内部LinkedIn BufferNode PreviousNode{get;set;}
内部LinkedRingBufferNode下一个节点{get;private set;}
}
}
但不幸的是,我对多线程环境有点陌生,那么如何使这个缓冲区线程对多次读写是安全的呢
谢谢 我认为最简单的方法是有一个同步
对象
,每当执行线程关键代码时,您都会打开它。块中的代码称为,一次只能由一个线程访问。任何其他希望访问它的线程都将等待,直到释放锁
定义和初始化:
private object Synchro;
public LinkedRingBuffer(int capacity)
{
Synchro = new object();
// Other constructor code
}
public T GetFirst()
{
lock(Synchro)
{
return firstNode.Item;
}
}
用法:
private object Synchro;
public LinkedRingBuffer(int capacity)
{
Synchro = new object();
// Other constructor code
}
public T GetFirst()
{
lock(Synchro)
{
return firstNode.Item;
}
}
在编写线程安全代码时,锁定
某些部分似乎是显而易见的。但是,如果您不确定是否要锁定语句或代码块,为了读写安全,您需要考虑:
- 此代码是否会影响任何其他锁定关键部分的行为或结果
- 任何其他锁定的关键部分是否会影响此代码的行为或结果