我知道链表不是线程安全的,而且在工作中我被要求编写一个简单的线程安全链表。
由于我不会经历的各种复杂情况,我不能简单地包装LinkedList但需要编写LinkedList的实现
我猜我需要这个,但是我怎样才能以线程安全的方式实现枚举器(对于有线列表)?
public class LinkedlistNode
{
private LinkedlistNode next;
private T item;
/// <summary>
/// Constructor for a new LinklistNode
/// </summary>
/// <param name="node">The node item to create</param>
public LinkedlistNode(T node)
{
next = null;
item = node;
}
/// <summary>
/// Shows the next item in the collection (or shows null for the the last item)
/// </summary>
public LinkedlistNode Next
{
get { return next; }
set { next = value; }
}
/// <summary>
/// The contents of the list
/// </summary>
public T Item
{
get { return item; }
set { item = value; }
}
}
答案 0 :(得分:3)
良好的开端。首先,我将通过包含类似于Next的Previous属性来双重链接列表。
使链接列表线程安全的主要问题是,与索引集合不同,最多必须同时锁定三个对象才能执行添加和删除。例如,如果另一个线程通过列表枚举,则会增加死锁的可能性;添加/删除线程需要锁定第四个节点以删除第五个节点,而枚举线程已经锁定了第四个项目并需要锁定第五个节点。单链表会有同样的问题,因为该算法需要另一个枚举顶部确定“前一个”节点,最终会阻塞尝试到达第四个项目,该项目已被第一个枚举器锁定,等待到达第五项。
我想有一个很大的问题要问:你究竟需要添加和删除项目?如果此实现将用作堆栈或队列后面的集合,则使其变得更容易线程安全,因为不允许枚举列表,并且当前列表中的节点只有端点节点(一个用于堆栈,一个用于队列)需要在添加/删除时锁定,除非堆栈或队列只有一个项目,否则锁定这些节点只会阻止其他尝试添加或删除的线程。
如果这是一个完整的链接列表实现,在导航到任何项目以及从任何地方添加和删除方面需要与List类似的功能,那么我认为最好的办法是隐藏一个将自行锁定的包装器后面的节点在执行任何操作之前,很像Interlocked对整数类型的操作。这绝不是一种“细粒度”的做法;任何想要对列表做任何事情的线程都必须等待。尝试允许多线程同时访问时,死锁的可能性太大。
对于没有死锁的细粒度,线程安全锁定的唯一希望是始终以列表将被枚举的相同顺序获取锁,并且仅允许在一个方向上进行迭代。基本上,这需要您隐藏双向链表的“上一个”节点,并允许节点在其他节点上获取“持久”锁。
答案 1 :(得分:0)
在本问题/答案中,对于多线程情况下SLL的实施有广泛的答案:
Thread-safe deletion of a linked list node, using the fine-grained approach