使用std :: mutex成员和运算符<<线程安全访问std :: ofstream成员插入过载?

时间:2016-04-12 20:55:11

标签: c++ operator-overloading ofstream

我正在尝试创建一个具有std :: ofstream和std :: mutex的类,这个类被锁定和解锁以控制对ofstream的访问。

基本上我想要一个类thread_safe_ofstreamwith<<运算符所以我可以使用它:

    thread_safe_ofstream ofs;

    ofs << "debug info from different threads" << std::endl;

所以我知道我需要一个运算符&lt;&lt;超载。虽然这个运营商有足够的信息&lt;&lt;对于&lt;&lt;的右侧的类,我找不到任何关于如何实现自己类似ostream的文档&lt;&lt;输入

我知道以下代码无法正常工作,因为无论输入/输出要求是什么&lt;&lt;有,但这是我需要的课程的精神。

Class thread_safe_ofstream
{
    std::mutex mu;
    std::ofstream stream;
    template<typename T>
    operator<<(T& thing)
    {
        mu.lock();
        stream << thing;
        mu.unlock();
    }
};

这样一个thread_safe_ofstream就可以从多个线程中解决而没有问题(我的希望是)。

3 个答案:

答案 0 :(得分:0)

那样的东西?

template<typename T>
thread_safe_ofstream& operator<<(const T& thing)
{
    std::lock_guard<std::mutex> guard(mu);
    stream << thing;
    return *this;
}

但是,通常最好将operator <<实现为自由函数,而不是类成员。

答案 1 :(得分:0)

例如,您可以使用此类实现:

class thread_safe_ofstream
{
    std::mutex mu;
    std::ofstream stream;

    template<typename T>
    void put(const T& thing) {
        std::lock_guard<std::mutex> lock(mu);
        stream << thing;
    }

    friend template<typename T>
    thread_safe_ofstream& operator<<(thread_safe_ofstream& tsof, const T& value) {
        tsof.put(value);
        return tsof;
    }
};

答案 2 :(得分:0)

这是一个完整的类,它将打印来自ts_ofs << "print this message" << std::endl之类的命令的大部分无文本文本,但后续<<之间的另一个线程可能会开始打印。我怀疑可能有一个修复,但我不知道该怎么做。灵感来自this post

struct ts_ofstream
{
    std::ofstream ostream;
    std::mutex mu;

    //This is only for testing, you can initialize ostream however/wherever you like.
    void init(bool test = false)
    {
        ostream = std::ofstream("C:/Users/Joey/Desktop/THREAD_DEBUG.txt", ios::out);
        if (test) 
        {
            ostream << "Testing stream ";
            ostream << std::endl;
            ostream << "Testing complete" << std::endl;
        }
    }

    template <typename T>
    friend ts_ofstream& operator<<(ts_ofstream& s, const T& x);

    // function that takes a custom stream, and returns it
    typedef ts_ofstream& (*MyStreamManipulator)(ts_ofstream&);

    // take in a function with the custom signature
    ts_ofstream& operator<<(MyStreamManipulator manip)
    {
        // call the function, and return it's value
        return manip(*this);
    }

    // define the custom endl for this stream.
    // note how it matches the `MyStreamManipulator`
    // function signature
    static ts_ofstream& endl(ts_ofstream& stream)
    {
        // print a new line
        stream.ostream << std::endl;

        return stream;
    }

    // this is the type of std::ofstream
    typedef std::basic_ostream<char, std::char_traits<char> > CoutType;

    // this is the function signature of std::endl
    typedef CoutType& (*StandardEndLine)(CoutType&);

    // define an operator<< to take in std::endl
    ts_ofstream& operator<<(StandardEndLine manip)
    {
        // call the function, but we cannot return it's value
        manip(this->ostream);
        return *this;
    }
};

template<typename T>
ts_ofstream & operator<<(ts_ofstream & s, const T & x)
{
    std::lock_guard<std::mutex> lock(s.mu);
    s.ostream << x;
    return s;
}