微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么互斥锁不适用于链表实现的线程安全队列类?

如何解决为什么互斥锁不适用于链表实现的线程安全队列类?

我用链表实现了一个队列,我希望多个线程以正确的顺序推送元素。我使用互斥锁来锁定我的成员函数,但是打印到终端的数字仍然没有正确的顺序,应该是 1,2,3,4,5,6。相反,它会打印错误的顺序,例如 3,1,6。这意味着互斥锁没有工作。有人可以告诉我为什么吗?以及如何解决这个问题?

// Implement a queue<int>,need functions: push_front,back,pop_back,and print
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;

struct ListNode { 
    ListNode* next;
    int val;
    ListNode(int x) {
        val = x;
        this->next = nullptr;
    }
};

class Queue {
    
public:
    Queue() {
        head = new ListNode(0); // dummy head
        tail = head;
    }

    
    void push_front(int x) { // add node at then end of linked list
        lock_guard<mutex> lock(m);
        tail->next = new ListNode(x);
        tail = tail->next;
        
    }

    int pop_back() { // remove the first node of the linked list
        lock_guard<mutex> lock(m);
        ListNode* back = head->next;
        if (back == nullptr) {
            throw invalid_argument("empty queue");
        }
        head->next = back->next;
        back->next = nullptr;
        return back->val;
    }

    void print() {
        lock_guard<mutex> lock(m);
        ListNode* p = head->next;
        while (p != nullptr) {
            cout << p->val << endl;
            p = p->next;
        }
    }

private:
    mutable mutex m;
    // Implement with linked list
    ListNode* head;
    ListNode* tail;
};


int main() {
    Queue* queue = new Queue();

    // Multiple threads push at the same time --> order is wrong
    thread t1 = thread(&Queue::push_front,queue,1);
    thread t2 = thread(&Queue::push_front,2);
    thread t3 = thread(&Queue::push_front,3);
    thread t4 = thread(&Queue::push_front,4);
    thread t5 = thread(&Queue::push_front,5);
    thread t6 = thread(&Queue::push_front,6);
    t1.join();
    t2.join();
    t3.join();
    t4.join();
    t5.join();
    t6.join();

    queue->print();
}

解决方法

正如许多用户所提到的,您对互斥锁含义的假设至少在(线程)顺序方面是错误的。在多线程上下文中,顺序通常是一种品质,它几乎总是系统地产生于您的业务逻辑和拟合数据类型,而不仅仅是来自单个编译器/语言内在函数。

您可以使用简单的单线程连续方法解决您的问题,或者,根据您的进一步目的,您可以将基础数据类型更改为支持偏序的类型(例如在 std::set 的意义上) ) 与并行写入访问相结合(不单独提及单个容器互斥锁,从而将整个并行方法减少到荒谬程度)。有些事情在这里是可能的,但这实际上取决于您的实际具体要求。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。