使用<<运算符与自己的函数一起 "覆盖 "cout。

问题描述 投票:0回答:1

我知道有很多关于重载<<运算符的话题,但是为了让它支持<<运算符,似乎总是在类中使用。希望我不会重复

我想做的是(我认为)完全不同的(可能更简单).我有一个有2个线程的控制台应用程序,都在控制台写东西。我想避免它们在控制台中互相碰撞,所以我使用了一个mutex来防止一个线程在另一个线程输出的时候,所以我创建了这个函数。

void print(string s){
    globals::console_mtx.lock();
    cout << s << endl;
    globals::console_mtx.unlock();
}

我希望它能像这样使用,无论数据类型如何。

int i=5;
print << "Some text" << i << endl;

我需要的是<<重载吗? 最简单的方法是什么?

谅谅

c++ operator-overloading cout
1个回答
0
投票

你想的是这个吗?

struct print_t {};
static const print_t print = print_t();

print_t& operator<<(print_t& p, const std::string& s) {
    globals::console_mtx.lock();
    std::cout << s << endl;
    globals::console_mtx.unlock();
    return p;
}

NB. 有十几种方法可以让它变得更好,比如将print作为一个具有唯一类型的函数,等等,以确保你不会遇到静态(de)初始化顺序的惨败(如果可能的话,在静态去初始化中避免上述情况)。你可以使用 cout 在std中作为一个小抄。


0
投票

只重载<<的问题是。

print << "Some text" << i << endl;

实际上是分别调用print.operator<<()来调用 "Some text", i, 和 endl (你还需要确保int和 endl有重载). 如果你对每个调用都进行锁定和解锁,那么另一个线程可能会在你完成所有3个调用之前得到锁。例如,如果线程2有

print << "Other text" << i+1 << endl;

那么你可能最终会发现。

"Some TextOther Text65\n\n"

最简单的处理方法是先输出到stringstream中 然后用普通的print函数打印出整个被锁住的mutex保护的东西。

stringstream ss;
ss <<"Some text" << i << endl;
print(ss.str());

如果你坚持直接使用流,那么流处理这种事情的方法是,只有当它接收到刷新的指令时才会写,endl会自动刷新流,这是它与"\n "不同的地方之一。

然后你实现一个自定义的std::stringbuf,锁定mutex并在sync()时输出到console,然后你为每个线程构造一个ostream作为它个人的打印输出流。

示例代码。

#include <iostream>
#include <sstream>
#include <mutex>
#include <thread>
#include <string>

// Increase risk of race condition if one can be triggered.
char slow_get_ch(char ch)
{
    for (unsigned int i = 0; i < 10000; ++i)
    {
        for (unsigned int j = 0; j < 10000; ++j)
        {
        }
    }

    return ch;
}

class print_buf : public std::stringbuf
{
    std::mutex& mtx_;

public:
    print_buf(std::mutex& mtx)
        :
        mtx_(mtx)
    {
    }

protected:
    int sync() final
    {
        std::unique_lock<std::mutex> lck(mtx_);
        std::string val = this->str();
        std::cout << val;
        this->str("");

        return 0;
    }
};

void print_worker(std::ostream* print_stream_ptr,char ch)
{
    std::ostream& print = *print_stream_ptr;

    // Print 5 lines of 20 times ch.
    for (unsigned int i = 0; i < 5; ++i) {
        for (unsigned int j = 0; j < 20; ++j) {
            print << slow_get_ch(ch);
        }
        print << std::endl;
    }
}

int main()
{
    std::mutex print_mutex;
    print_buf buf1(print_mutex);
    print_buf buf2(print_mutex);
    print_buf buf3(print_mutex);

    std::ostream p1(&buf1);
    std::ostream p2(&buf2);
    std::ostream p3(&buf3);

    std::thread t1(print_worker, &p1, 'a');
    std::thread t2(print_worker, &p2, 'b');
    std::thread t3(print_worker, &p3, 'c');

    t1.join();
    t2.join();
    t3.join();

    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.