我正在尝试控制模拟中的输出打印。它打印了很多输出流信息。这是我尝试控制输出流的示例代码。有时我想打印每个线程的信息,有时我不希望线程中的单个打印减少模拟中的系统调用。我传递命令行参数来控制流。参数v
表示没有打印件。问题是它需要在整个模拟器中使用大量if
语句。有没有简单的方法来处理这个问题?
#include <iostream>
#include <thread>
void work_to_do_1(char ch)
{
//work for thread 1
if(ch != 'v')
std::cout << "-:Thread 1:-" << std::endl;
}
void work_to_do_2(char ch)
{
if (ch != 'v')
std::cout << "-:Thread 2:-" << std::endl;
}
void work_to_do_3(char ch)
{
if (ch != 'v')
std::cout << "-:Thread 3:-" << std::endl;
}
int main(int argc, char *arg[])
{
std::cout << "You have entered " << argc
<< " arguments:" << "\n";
for (int i = 0; i < argc; ++i)
{
std::cout << arg[i] << "\n";
}
char t = *arg[1];
std::cout << "manager is running" << std::endl;
std::thread t1(work_to_do_1, t);
std::thread t2(work_to_do_2, t);
std::thread t3(work_to_do_3, t);
t1.join();
t2.join();
t3.join();
system("pause");
return 0;
}
答案 0 :(得分:0)
创建自己的nul流:
struct cnul_t : std::basic_ostream<char> {} cnul;
template<class T> std::ostream& operator<<(cnul_t& os, T const&) { return os; }
并将输出重定向到它以忽略它:
#include <ostream>
#include <iostream>
struct cnul_t : std::basic_ostream<char> {} cnul;
template<class T> std::ostream& operator<<(cnul_t& os, T const&) { return os; }
void maybe_log(bool b)
{
std::ostream& out = b == true ? std::cout : cnul;
out << "Hello, World!\n";
}
int main()
{
maybe_log(true); // outputs Hello, World!
maybe_log(false); // no output
}
答案 1 :(得分:0)
This answer很好地解释了这个问题。虽然ostream
本身就是线程安全的(因为C ++ 11),std::cout << "-:Thread 1:-" << std::endl;
之类的内容实际上是对std::cout.operator<<
的两个调用,而另一个线程可能会介于两者之间他们因此扼杀你的输出。我想,你可以这样做。
因此,从this post无耻地窃取代码我谦卑地提交以下解决方案(也有一个全局标记,gLogging
,以打开或关闭日志记录)。每次登录std::endl
时,这都会将行写入std :: cout 原子。我写这篇文章是为了培养自己的个人技能,我想你可能会喜欢它。
有关如何检测std::endl
的说明,请参阅链接的帖子,但基本原则是每个线程的单独日志缓冲区,当它具有完整的输出行时,将刷新到std::cout
摆脱。该代码包含一个管理器类(Logger
),用于处理创建,销毁和访问这些缓冲区的详细信息。您只需要在每个线程的开头放置两行初始化代码,如图所示,然后记录到logstream
而不是std::cout
。
#include <iostream>
#include <sstream>
#include <mutex>
#include <map>
#include <thread>
bool gLogging = true;
constexpr int bufsize = 512; // needs to be big enough for longest logging line expected
// A streambuf that writes atomically to std::cout when (indirectly) it sees std::endl
class LogBuf : public std::stringbuf
{
public:
LogBuf () { setbuf (m_buf = new char [bufsize], bufsize); str (""); }
~LogBuf () { delete [] m_buf; }
protected:
// This gets called when the ostream we are serving sees endl
int sync() override
{
if (gLogging)
{
std::cout << str();
std::cout.flush();
}
str("");
return 0;
}
private:
char *m_buf;
};
// An ostream that uses LogBuf
class LogStream : public std::ostream
{
public:
LogStream () : std::ostream (m_LogBuf = new LogBuf ()) { }
~LogStream () { delete m_LogBuf; }
private:
LogBuf *m_LogBuf;
};
// A class to manage LogStream objects (one per thread)
class Logger
{
public:
void AddThread (void)
{
mutex.lock ();
m_logstreams [std::this_thread::get_id ()] = new LogStream ();
mutex.unlock ();
}
void RemoveThread ()
{
mutex.lock ();
std::thread::id thread_id = std::this_thread::get_id ();
LogStream *logstream = m_logstreams [thread_id];
m_logstreams.erase (m_logstreams.find (thread_id));
mutex.unlock ();
delete logstream;
}
LogStream& GetLogStream ()
{
mutex.lock ();
LogStream *logstream = m_logstreams [std::this_thread::get_id ()];
mutex.unlock ();
return *logstream;
}
private:
static std::mutex mutex;
std::map<const std::thread::id, LogStream *> m_logstreams;
};
std::mutex Logger::mutex;
Logger logger;
// A simple class to make sure we remember to call RemoveThread
class LogStreamHelper
{
public:
LogStreamHelper () { logger.AddThread (); }
~LogStreamHelper () { logger.RemoveThread (); }
inline LogStream &GetLogStream () { return logger.GetLogStream (); }
};
// Test program
void work_to_do_1()
{
LogStreamHelper logstream_helper;
LogStream& logstream = logstream_helper.GetLogStream ();
logstream << "-:Thread 1:-" << std::endl;
}
void work_to_do_2()
{
LogStreamHelper logstream_helper;
LogStream& logstream = logstream_helper.GetLogStream ();
logstream << "-:Thread 2:-" << std::endl;
}
int main ()
{
LogStreamHelper logstream_helper;
LogStream& logstream = logstream_helper.GetLogStream ();
logstream << "Main thread" << std::endl;
std::thread t1 (work_to_do_1);
std::thread t2 (work_to_do_2);
t1.join ();
t2.join ();
return 0;
}
输出:
Main thread
-:Thread 1:-
-:Thread 2:-
在Wandbox运行。