非线程安全类的异步多线程安全模型

别等时光非礼了梦想. 提交于 2019-12-26 04:41:54

 在项目中经常会遇到一些需要异步处理的(耗时长)并且线程不安全的对象在多线程模型中使用,封装了一个实用的线程模板,用于直接处理这类的事务。将该线程不安全的对象直接绑定到单个线程上,然后将一个外部处理函数压入队列,由该线程取出对象和处理函数调用。绑定的对象作为第一个参数传入处理函数中,其余入参依次传入函数的实参。

代码如下, 版本:c++14, 编译器:gcc 5.4

#include <thread>
#include <iostream>
#include <functional>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <chrono>

template<typename INSTANCE>
class SafeThread
{
public:
    SafeThread(std::shared_ptr<INSTANCE> i) : instance(i)
    {
        worker = std::thread([this] {
            while(!this->stop)
            {
                std::function<void()> task;
                {
                    std::unique_lock<std::mutex> lck(this->queue_mtx);
                    this->condition.wait(lck, [this] { return this->stop || !this->tasks.empty();} );
                    if (this->stop)
                    {
                        break;
                    }
                    else if (this->tasks.empty())
                    {
                        throw std::runtime_error("consume an empty task");
                    }
                    task = std::move(this->tasks.front());
                    this->tasks.pop();
                }
                task();
            }
        });

    }

    virtual ~SafeThread()
    {
        stop = true;
        std::unique_lock<std::mutex> lck(queue_mtx);
        condition.notify_all();
        worker.join();
    }

    template<typename F, typename... Args>
    void Insert(F f, Args... args)
    {
        auto task  = std::bind(std::forward<F>(f), instance, std::forward<Args>(args)...);
        std::unique_lock<std::mutex> lck(queue_mtx);
        if (stop)
        {
            throw std::runtime_error("insert into a stopped thread");
        }
        tasks.emplace(task);
        condition.notify_one();

    }

private:
    std::shared_ptr<INSTANCE>     instance;
    std::thread                   worker;
    std::queue<std::function<void()>> tasks;
    std::mutex                    queue_mtx;
    std::condition_variable       condition;
    bool                          stop = false;
};


// a non-thread-safe class
class UnSafe
{
public:
    void add(int x, int y)
    {
        while(y -- > 0)
        {
            counts += x;
        }
    }

    void print()
    {
        std::cout << "counts : " << counts << std::endl;
    }

    int counts = 0;
};


using namespace std::chrono_literals;
int main()
{
    int cnts = 10000;
    const int interval = 5;
    const int times = 10;
    auto us = std::make_shared<UnSafe>();
    while(cnts -- > 0)
    {
        std::thread([&us] () {
            us->add(interval, times);
        }).detach();
    }
    std::this_thread::sleep_for(3s);
    us->print();


    cnts = 10000;
    us->counts = 0;
    SafeThread<UnSafe> st(us);
    while(cnts -- > 0)
    {
        std::thread([&st] () {
            st.Insert([] (std::shared_ptr<UnSafe> _us, int _interval, int _times) {
                _us->add(_interval, _times);
            }, interval, times);
        }).detach();
    }
    std::this_thread::sleep_for(3s);
    us->print();


    std::string end = "";
    while(std::cin >> end)
    {
        if (tolower(end.at(0)) == 'q')
        {
            break;
        }

    }
}

执行结果:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!