线程安全堆栈互斥体在忙碌时被破坏

时间:2015-02-15 17:40:21

标签: c++ multithreading thread-safety stack mutex

我已经学习了一段时间的C ++标准库多线程,作为练习,我想使用互斥锁和条件变量来创建一个线程安全的堆栈。这是我上课的时间:

#ifndef THREADSAFE_STACK_H_
#define THREADSAFE_STACK_H_
#include <mutex>
#include <condition_variable>
#include <stack>
#include <memory>


template <typename T> class threadsafe_stack
{
    public:
        mutable std::mutex mut;
        std::stack<T> st;
        std::condition_variable cond;

    public:
        threadsafe_stack() = default;
        threadsafe_stack(const threadsafe_stack &s);
        threadsafe_stack(threadsafe_stack &&s);
        threadsafe_stack& operator=(const threadsafe_stack &s);
        threadsafe_stack& operator=(threadsafe_stack &&s);

        void push(const T &t);
        void push(T &&t);

        bool try_pop(T &t);
        std::shared_ptr<T> try_pop();

        void wait_and_pop(T &t);
        std::shared_ptr<T> wait_and_pop();

        typename std::stack<T>::size_type size() const;
        bool empty() const;
};


template <typename T> threadsafe_stack<T>::threadsafe_stack(const threadsafe_stack &s)
{
    std::lock(mut, s.mut);
    std::lock_guard<std::mutex> lock1(mut, std::adopt_lock);
    std::lock_guard<std::mutex> lock2(s.mut, std::adopt_lock);
    st = s.st;
}


template <typename T> threadsafe_stack<T>::threadsafe_stack(threadsafe_stack &&s)
{
    std::lock(mut, s.mut);
    std::lock_guard<std::mutex> lock1(mut, std::adopt_lock);
    std::lock_guard<std::mutex> lock2(s.mut, std::adopt_lock);
    st = std::move(s.st);
}


template <typename T> threadsafe_stack<T>& threadsafe_stack<T>::operator=(const threadsafe_stack &s)
{
    if (this == &s)
        return *this;

    std::lock(mut, s.mut);
    std::lock_guard<std::mutex> lock1(mut, std::adopt_lock);
    std::lock_guard<std::mutex> lock2(s.mut, std::adopt_lock);
    s = s.st;

    return *this;
}


template <typename T> threadsafe_stack<T>& threadsafe_stack<T>::operator=(threadsafe_stack &&s)
{
    std::lock(mut, s.mut);
    std::lock_guard<std::mutex> lock1(mut, std::adopt_lock);
    std::lock_guard<std::mutex> lock2(s.mut, std::adopt_lock);
    s = std::move(s.st);
}


template <typename T> void threadsafe_stack<T>::push(const T &t)
{
    std::lock_guard<std::mutex> lock(mut);
    st.push(t);
    cond.notify_one();
}


template <typename T> void threadsafe_stack<T>::push(T &&t)
{
    std::lock_guard<std::mutex> lock(mut);
    st.push(std::move(t));
    cond.notify_one();
}


template <typename T> bool threadsafe_stack<T>::try_pop(T &t)
{
    std::lock_guard<std::mutex> lock(mut);
    if (st.empty())
        return false;

    t = st.top();
    st.pop();
    return true;
}


template <typename T> std::shared_ptr<T> threadsafe_stack<T>::try_pop()
{
    std::lock_guard<std::mutex> lock(mut);
    if (st.empty())
        return std::shared_ptr<T>();

    std::shared_ptr<T> result(new T{st.top});
    st.pop();
    return result;
}


template <typename T> void threadsafe_stack<T>::wait_and_pop(T &t)
{
    std::unique_lock<std::mutex> lock(mut);
    cond.wait(lock, [this]{ return !st.empty(); });

    t = st.top();
    st.pop();
}


template <typename T> std::shared_ptr<T> threadsafe_stack<T>::wait_and_pop()
{
    std::unique_lock<std::mutex> lock(mut);
    cond.wait(lock, [this]{ return !st.empty(); });

    std::shared_ptr<T> result(new T{ st.top });
    st.pop();
    return result;
}


template <typename T> typename std::stack<T>::size_type threadsafe_stack<T>::size() const
{
    std::lock_guard<std::mutex> lock(mut);
    return st.size();
}


template <typename T> bool threadsafe_stack<T>::empty() const
{
    std::lock_guard<std::mutex> lock(mut);
    return st.empty();
}


#endif

然后我想在一个像这样的简单程序中测试它:

#include <iostream>
#include <condition_variable>
#include <ctime>
#include <chrono>
#include <thread>
#include "threadsafe_stack.h"


threadsafe_stack<int> data_stack;
void process_data()
{
    while (true)
    {
        int val = 0;
        data_stack.wait_and_pop(val);
        std::cout << val << " ";
    }
}


int main()
{
    std::thread processor(process_data);
    processor.detach();

    int values[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for (int i = 0; i < 10; i++)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        data_stack.push(values[i]);
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    system("pause");
    return 0;
}

输出结果为:

1 2 3 4 5 6 7 8 9 10 Press any key to continue . . .
f:\dd\vctools\crt\crtw32\stdcpp\thr\mutex.c(40): mutex destroyed while busy

在我按任意键或尝试关闭控制台后立即出现第二行。除了附加消息,我得到一个错误(我猜是未处理的异常?)听起来像我在退出程序时使用互斥锁但它不应该因为条件变量wait应该在等待时解锁它。我很无能。

1 个答案:

答案 0 :(得分:1)

这是因为程序退出,这会破坏全局变量。如果你想等到程序完成工作,你需要加入底部的processor线程(而不是分离它)。

条件变量只能使其他线程休眠,而不是主线程。