【问题标题】:ThreadSafe Queue c++线程安全队列 C++
【发布时间】:2020-01-14 13:20:04
【问题描述】:

我正在尝试借助 std::mutexstd::condition_variable 在 C++ 中创建线程安全队列。代码

#include <iostream>
#include<thread>
#include<queue>
#include<atomic>
#include<mutex>
#include<condition_variable>

using namespace std;

template<class T>
class SafeQueue{
public:
    queue<T>qu;
    mutex mut;
    condition_variable cv;
    SafeQueue(){}
    SafeQueue(queue<T>q):qu(q){}
    void push(int val){
        unique_lock<mutex>uq(mut);
        cv.wait(uq,[&](){return qu.empty();});
        qu.push(val);
        uq.unlock();
    }
    bool isEmpty(){
//      unique_lock<mutex>uq(mut);
//      uq.unlock();
        cv.notify_all();
        return qu.empty();
    }
};
void inc(SafeQueue<int>& sq){
    for(int i=0;i<10;i++)
        continue;
    if(sq.isEmpty())
        sq.push(1);
}
void inc1(SafeQueue<int>& sq){
    for(int i=0;i<10;i++)
        continue;
    if(sq.isEmpty())
        sq.push(2);
}

int main(){
    queue<int>qu;
    SafeQueue<int> sq(qu);
    thread t1(inc,ref(sq));
    thread t2(inc1,ref(sq));
    t1.join();
    t2.join();
    cout<<sq.qu.front();
}

线程安全队列应该在最后输出1,但输出是随机的12,这意味着它不是线程安全的。为什么这个特定的程序不起作用?

【问题讨论】:

标签: c++ multithreading condition-variable


【解决方案1】:

并不意味着程序不是线程安全的。这并不意味着它定义不明确并且会崩溃。

这只是意味着您的程序逻辑不是以任何特定顺序将项目添加到队列中。

如果您希望以特定顺序添加这两个项目,请从 一个 线程推送两者。

线程安全并不意味着您的应用程序就像只有一个线程一样运行。

您的程序运行良好。

【讨论】:

  • 但我的实际答案应该是 1,因为我先推送它,然后函数 inc1() 将运行,这就是我想要实现的更像并发过程。如果我错了你能为我提供一个有效的逻辑来实现。还有一件事,当我在两个线程中使用相同的函数时,它只是在运行时挂起(等待线程完成),但我认为在这种情况下不会产生任何死锁情况.
  • @AbhinavSingh 你在什么意义上“先推动它”?两个线程同时运行(“同时”)。这就是线程的全部意义所在。如果您不想要并发,请不要使用并发。
  • 能否请你让我清楚什么是线程安全队列(我是多道程序的新手)是我想要的吗?抱歉这个奇怪的问题?
  • @AbhinavSingh 我不知道你想要什么。您应该查看有关多线程编程的书。
  • @AbhinavSingh 你不能只是在一个问题上抛出线程来“让它变快”。这不是它的工作原理。你的程序将是最快的,并且满足你的需求,如果你真的只是要求它“推 1”,然后要求它“推 2”。按顺序,按顺序。就是这样。让这两件事“同时”发生并没有完成任何事情,除了删除该排序约束。这不是线程的用途。当您有几个 [大部分] 不相关的操作时,您可以使用线程,这些操作最好并行发生以节省时间,或者因为一个或另一个 阻塞,或者使用多个 CPU。
【解决方案2】:

您的代码有几个方面存在缺陷:

  • 无论何时访问共享结构,都必须由互斥体保护。你有一个互斥体,但你没有在isEmpty() 中使用它。记录该连接,这很重要,不要迷失方向。此外,对 CV 执行相同的操作,记录何时发出信号。
  • 关于isEmpty(),这个功能无论如何都没用。即使队列在某个时间点不是空的,也没有什么可以阻止它在下一秒变空。
  • 重新阅读unique_lock 的文档。您使用它的方式比必要的复杂。
  • CV 的使用也很奇怪:通常,你用它来通知服务员有变化。您在似乎只查询某些状态的函数中无条件地发出信号。

【讨论】:

  • 我在 isEmpty 中使用互斥锁(函数 isEmpty() 中的注释代码),但它不起作用并产生相同的结果,所以我取消注释它以查看它是否给我正确的输出。关于unique_lock我觉得是我上面写的程序里用的。
  • 好吧,那么你在这里发布的问题很糟糕:我只能评论你提供的代码,而不是你在其他地方或以前尝试过的代码。说清楚!
猜你喜欢
  • 2013-02-23
  • 2014-03-13
  • 1970-01-01
  • 2023-03-04
  • 1970-01-01
  • 2015-02-16
  • 2012-11-05
  • 2010-11-15
  • 1970-01-01
相关资源
最近更新 更多