Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 无锁列表删除操作_Multithreading_Concurrency_Synchronization_Locking_Lock Free - Fatal编程技术网

Multithreading 无锁列表删除操作

Multithreading 无锁列表删除操作,multithreading,concurrency,synchronization,locking,lock-free,Multithreading,Concurrency,Synchronization,Locking,Lock Free,我有以下问题定义: 使用以下操作设计无锁简单链表: 添加(项):将节点添加到列表的开头(标题) 移除(项):从列表中移除给定项 下面显示了迄今为止实现的代码: public class List<T> { private readonly T _sentinel; private readonly Node<T> _head; public List() { _head = new Node<T>();

我有以下问题定义:

使用以下操作设计无锁简单链表:

  • 添加(项):将节点添加到列表的开头(标题)
  • 移除(项):从列表中移除给定项
下面显示了迄今为止实现的代码:

public class List<T>
{
    private readonly T _sentinel;
    private readonly Node<T> _head;

    public List()
    {
        _head = new Node<T>();
        _sentinel = default(T);
    }

    public List(T item)
    {
        _head = new Node<T>(item);
        _sentinel = item;
    }

    public void Add(T item)
    {
        Node<T> node = new Node<T>(item);

        do
        {
            node.Next = _head.Next;
        }
        while (!Atomic.CAS(ref _head.Next, node.Next, node));
    }

    public void Remove(Node<T> item)
    {
        Node<T> next;
        Node<T> oldItem = item;  

        if (item.Value.Equals(_sentinel))
            return;

        item.Value = _sentinel;

        do
        {
            next = item.Next;

            if (next == null)
            {
                Atomic.CAS(ref item.Next, null, null);
                return;
            }

        } while (!Atomic.CAS(ref item.Next, next, next.Next));

        item.Value = next.Value;
    }
}
公共类列表
{
私人只读T_哨兵;
专用只读节点头;
公开名单()
{
_头=新节点();
_sentinel=默认值(T);
}
公众名单(T项)
{
_head=新节点(项目);
_哨兵=物品;
}
公共作废新增(T项)
{
节点=新节点(项目);
做
{
node.Next=\u head.Next;
}
而(!Atomic.CAS(ref_head.Next,node.Next,node));
}
公共作废删除(节点项)
{
节点下一步;
节点oldItem=项目;
if(item.Value.Equals(_sentinel))
返回;
项目值=_sentinel;
做
{
下一个=项目。下一个;
if(next==null)
{
Atomic.CAS(ref item.Next,null,null);
返回;
}
}而(!Atomic.CAS(ref item.Next,Next,Next.Next));
item.Value=next.Value;
}
}
头部实际上是一个为便于使用而保留的虚拟(哨兵)节点。实际的头实际上是下一个。 尝试删除列表的最后一个元素时,删除操作出现问题:

在拆卸零件上有两种情况:

  • 该节点具有以下NOTNULL next指针:然后执行CAS操作并窃取下一项的值数据,实际删除下一项
  • 有问题的情况是,要删除的元素是列表中的最后一个元素:
    • 原子地执行:如果(item==oldItem和item.Next==null),则item=null,其中oldItem是指向要删除的项的指针
  • 所以我要做的是在移除C节点的情况下:

    • 如果(C==old-C-reference和C.Next==null),则C=null=>所有原子
    问题是我只有一个对象上的CAS。 我如何以原子方式解决这个问题?或者有没有更好的方法来完成我在这里错过的移除操作

    当删除B时,我们通过将C的内容复制到B并在移动成功后删除C:B.Next=C.Next(在循环中)和B.Value=C.Value来执行一个技巧

    因此,您需要原子地修改两个内存位置。NET中的CAS不支持这一点。但是,您可以将这两个值包装到另一个可以原子交换的对象中:

    class ValuePlusNext<T> {
     T Value;
     Node<T> Next;
    }
    
    class Node<T> {
     ValuePlusNext<T> Value;
    }
    

    你确定“哨兵”的方法有效吗?对于值类型,无法区分默认值(T)和可能有用的值。换句话说,.NET类型系统不提供可用作sentinel的值。事实上,sentinel值可能不适用于值类型,但为了便于使用,让我们将预定义标记定义为sentinel。如果你知道更好的解决方案,请分享()。然而,我的主要问题是移除操作。你的移除对我来说毫无意义。如果你想删除B,那么你需要在C旁边加上A,对吗?你的代码不能做到这一点。我承认这是我第一次处理原子链表。正如问题中提到的,当删除B时,我们会将C的内容复制到B,然后删除C:B.Next=C.Next(在循环中)和B.Value=C.Value。移动成功后,这不会起作用,因为它只会检查引用,而不会检查其中的值。我可以自由更改节点。下一个值和具有另一个节点(或对该节点的另一个引用)的CA将成功,因为它们具有相同的引用,即使该节点。下一个值已更改。引用类型的CAS检查引用指向的内存位置,但是我对检查值感兴趣。ValuePlusNext字段应该永远不会更改。如果要更改它们,请创建新的ValuePlusNext并将其固定到位。这样您就可以安全地检查和比较字段。这样行吗?然后,您可以将CAS更新建立在对ValuePlusNext对象的对象引用在此期间没有更改的条件下。我添加了一些代码。几乎。。。问题是CAS在相同的类型参数上工作,并且CAS(ref-Value,old,new)不会编译=>“new”的类型与old和Value类型不同。不确定您的意思。所有三个都应为ValuePlusNext类型。
    while (true) {
     var old = item.Value;
     var new = new ValuePlusNext(...);
     if (CAS(ref Value, old, new)) break;
    }