C++ 给定位置后的函数插入线程问题

C++ 给定位置后的函数插入线程问题,c++,linked-list,C++,Linked List,我正在尝试在链接列表中添加一个新节点。问题是我有一个并发问题,我不知道如何解决它 守则: void insert(Node* before, unsigned value){ Node* node = new Node; node->loadValue = value; Node* after = before->next; before->mtx.lock(); before->next = node;

我正在尝试在链接列表中添加一个新节点。问题是我有一个并发问题,我不知道如何解决它

守则:

 void insert(Node* before, unsigned value){
      Node* node = new Node;
      node->loadValue = value;
      Node* after = before->next;
      before->mtx.lock();
      before->next = node;
      before->mtx.unlock();
      after->mtx.lock();
      after->prev = node;
      after->mtx.unlock();
      node->prev = before;
      node->next = after;
 }

任何解决方案?

在编写并发代码时,需要考虑许多问题。并发编程需要良好的编程技能。对于您的案例(链表),您需要考虑:

  • 异常安全代码:当代码中抛出异常时,您需要确保所有锁定的
    互斥锁都被解锁
  • 避免:必须以不会使代码处于死锁状态的顺序锁定
    mutex
    s
  • 避免:当两个或多个线程在没有任何适当同步的情况下尝试访问共享数据时,会发生争用情况
让我们回到您的示例。(我假设您使用的是
C++11

异常安全代码:必须始终使用或在希望使用
std::mutex时使用:

std::lock_guard<std::mutex> lock(mutex);

建议:尽量不要自己编写并发容器。这是一个专业领域,需要很多经验才能找到正确的解决方案。有像英特尔TBB这样的并发库,您可以使用它

假设这不是家庭作业或某种学术/理论练习,我有两个简单的建议来修复您的代码:

  • 不要对每个操作都进行锁定/解锁。链接列表的速度足够慢,这么多的锁定操作只会让情况变得更糟(更不用说,如果列表可以在锁定之间更改,你几乎无法保护任何东西)。只需在开始时锁定它一次,然后在整个操作(插入、删除等)完成后释放它。事实上,您甚至不应该为此使用像互斥体这样重的东西,这就是关键部分存在的原因

  • 无论如何,您不应该使用链表,基于向量的实现在实践中几乎总是更好的。当然,您不应该自己动手,只需要使用STL提供的实现


  • 在->mtx之后,你在哪里锁定了
    ?我编辑了@MRB..好的,但是如果插入可以同时调用,但不能为同一位置调用呢?@chi变化不大。你需要考虑所有可能的状态。也许我们能找到另一个打破名单的州。类中的所有函数都必须是线程安全的。您需要考虑其他功能和所有限制来编写最终版本。但我所说的是编写并发链表或其他容器的一般规则(可能不完整)。@MRB,有没有其他不使用全局互斥的解决方案?@Nelly我所说的并不意味着你不能使用其他解决方案。OP想要实现
    细粒度并发链表
    ,我展示了一个他做错了的场景。通常,并发数据结构可以用三种方式实现:
    全局互斥体
    细粒度互斥体
    无锁
    。最后一个很难用正确的方式写,我不知道是否有一个完整的解决方案。我试图编写一个无锁实现,但。。。我决定避免进入这个区域。
    void insert(Node* before, unsigned value)
    {
        Node* node = new Node;
        node->loadValue = value;
    
        std::lock_guard<std::mutex> before_guard(before->mtx);
    
        Node* after = before->next;
    
        std::lock_guard<std::mutex> after_guard(after->mtx);
    
        before->next = node;
        after->prev = node;
        node->prev = before;
        node->next = after;
     }