线程安全流和流操纵器
我正在尝试编写一个线程安全的记录器类,以便我可以执行与 cout 完全相同的操作,但具有线程安全性。
这是记录器类(仍在处理所需的锁定类型)
class logger {
public:
logger(LOGGER::output_type type);
logger(const logger& orig);
virtual ~logger();
template <typename T>
logger & operator << (const T & data){
boost::mutex::scoped_lock io_mutex_lock(io_mutex);
(*out)<<data;
return *this;
}
private:
static boost::mutex io_mutex;
std::ostream * out;
};
问题是我无法执行以下操作
log<<"asdfg";
我必须这样做
log<
-
int i = 10;
log<<字符串(“i =”)<<我<< endl;
以下是编译错误。
gcc.compile.c++ src/simpleThread/bin/gcc-4.4.5/debug/simpleThread.o
src/simpleThread/simpleThread.cc: In function ‘int main()’:
src/simpleThread/simpleThread.cc:28: error: no match for ‘operator<<’ in ‘((logger*)logOut.logger::operator<< [with T = char [18]](((const char (&)[18])"fibonacci thread ")))->logger::operator<< [with T = int](((const int&)((const int*)(& i)))) << std::endl’
所以我想我错过了 C++ 的一些重要概念。请告诉我这是什么? 我的要求可以实现吗
谢谢 基兰
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
请注意,您的记录器类仍然不是线程安全的:
没有什么可以阻止该线程被另一个打印到记录器的线程抢占并生成类似的内容:
而不是:
如果您有一个带有可变参数模板的编译器,这是解决此问题的一种方法:
即互斥锁被锁定,直到处理给定日志消息的所有参数为止。
std::endl
通过在每条消息后始终刷新流来单独处理。Note that your logger class is still not thread safe:
There is nothing stopping this thread from getting preempted by another another thread printing to logger and producing something like:
Instead of:
If you have a compiler with variadic templates, here's one way of fixing this:
I.e. the mutex is locked until all arguments for given log message are processed.
std::endl
is handled separately by always flushing the stream after every message.您的问题是 logger 不是流,因此通常的流运算符将不起作用,只能使用您定义的单个流运算符。
您可以通过自己定义
endl
来工作:现在
log << “你好!” << endl;
会起作用。能够链接多个<<像流一样一起操作,您必须为记录器定义所有运算符(就像流一样)。
Your problem is that
logger
isn't a stream, so the usual stream operators will not work, just the single one you have defined.You can get
endl
to work by defining it yourself:Now
log << "Hello!" << endl;
will work.To be able to chain several << operations together like the streams do, you will have to define all the operators for the logger (just like the streams do).
我认为你在太低的水平上引入同步。要理解原因,假设线程 1 执行:
而线程 2 执行:
在这种情况下,日志文件(或控制台输出)可能包含交错的消息,例如:
为了避免此问题,您的应用程序将必须构建
将整个消息作为单个字符串,然后才将该字符串传递给记录器对象。例如:
如果您采用这种方法,那么您的记录器类不需要为
endl
和多种类型重载operator<<
。I think you are introducing synchronization at too low a level. To understand why, assume thread 1 executes:
while thread 2 executes:
In such a case, the log file (or console output) may contain interleaved messages, for example:
To avoid this problem, your application will have to construct
an entire message as a single string, and only then pass that string to a logger object. For example:
If you take this approach, then your logger class does not need to overload
operator<<
forendl
and multiple types.我通过一些简化测试了您的程序,如下所示,它编译并运行良好,这意味着问题可能出在其他地方:
I tested your program with some simplifications as follows, and it compiles and runs fine, which means that the problem is probably elsewhere:
在深入研究 iostreams 并根据 Bo Persson 的提示后,我认为我找到了更好的解决方案,因为我不需要为每个 ios 操纵器分别编写一个函数。所以这里是
iostreams 和应用程序的解释搜索。
这是完整的 boost:: 线程安全实现(可能需要一些重构和优化),使用 Ciaran-Mchale
像这样使用它
After digging into iostreams and with hints from Bo Persson, I think i found a better solutions since I dont need to write a function each for each ios manipulator. So here it is
For an explanation search for iostreams and applicators.
Here is the complete boost::thread safe implementation (requires some refactoring and optimization probably) using some hints from Ciaran-Mchale
use it like this