我知道有很多关于重载<<运算符的话题,但是为了让它支持<<运算符,似乎总是在类中使用。希望我不会重复
我想做的是(我认为)完全不同的(可能更简单).我有一个有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;
我需要的是<<重载吗? 最简单的方法是什么?
谅谅
你想的是这个吗?
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中作为一个小抄。
只重载<<的问题是。
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;
}