2010-12-15 49 views
2

创建我自己的std::cerr以便它是逐行线程安全的最简单方法是什么?C++的基于线程的线程安全的std :: cerr

我最好寻找代码来做到这一点。

我需要的是当我在控制台上看到它时,由一个线程生成的a line of output(以std :: endl结尾)保持as a line of output。 (并没有与其他线程的输出混合)

解决方案std::cerr比cstdio慢很多。我更喜欢在CriticalSectionLocker类中使用fprintf(stderr, "The message") whos的构造函数获得线程安全锁,并且desturctor释放它。

+1

你如何想像创建线程本地缓冲区 “上钩” 到'标准:: cerr'会减少线程本地缓冲区“外部”的缓冲区,然后将全部行写入'std :: cerr'?缓冲区是一个缓冲区。 'std :: ostringstream'是一个典型的通用方法。 – 2010-12-15 03:46:49

+3

你有没有机会寻找一个线程安全日志库? – yasouser 2010-12-15 03:47:27

+1

我最近了解到了log4cpp项目(http://log4cpp.sourceforge.net/)。不确定它是否提供你正在寻找的东西!?!?也许值得检查一下。 – yasouser 2010-12-15 04:01:19

回答

3

此:在大多数编译器

#define myerr(e) {CiriticalSectionLocker crit; std::cerr << e << std::endl;} 

作品的myerr("ERR: " << message << number)常见的情况。

+0

这假定你不想使用'<<'操作符来格式化(例如'cerr <<“这个日志消息已经被打印出来了<< << n次<< <<次。”<< endl;') – 2010-12-15 14:54:01

+2

Hrm。我其实是错的,因为我暂时忘记了宏是如何工作的。你需要做的所有事情都是调用'lerr(“这个日志消息已经被打印出来了”<< n次<<“次)”,而文本替换就会正确。 – 2010-12-15 18:53:11

5

你没有。没有任何关于std::cerr(也不是整个语言中的任何其他共享对象)可以知道哪个线程正在对<< operator进行特定呼叫以防止交织。

你能做的最好的是创建一批线程特定的日志对象,每个积累数据,直到达到一个换行符,然后收购,保护cerr以便同时保持一整行写在一次cerr的锁锁。

+0

这样经过良好测试的类库要多得多,我打算使用自己的类。我如何编写这些描述的基于iostream的记录器对象?那是我原来的问题。我对cerr <<“message” – unixman83 2010-12-15 04:13:42

+0

以外的iostreams一无所知。我不太确定。我认为有以下几种选择:#1你可以编写你自己的streambuf,将数据刷新到'cerr'并使用一个普通的ostream为它格式化数据,#2你可以在每个线程的记录器中使用一个'std :: stringstream'来累积数据(stringstream与所有'cerr'的格式化基元完全兼容,但是暴露它们更加有效)。在哪里获得锁定以清除cerr将是平台特定的。 #3你可以用'sprintf'做些什么,然后格式化字符串。 – 2010-12-15 04:19:55

+0

或者像log4cpp – 2010-12-15 04:21:35

2

对unixman评论中的方法进行了改进(并不真正适合评论)。

#define LOCKED_ERR \ 
    if(ErrCriticalSectionLocker crit = ErrCriticalSectionLocker()); \ 
    else std::cerr 

如果ErrCriticalSectionLocker是认真落实其中可用于像

LOCKED_ERR << "ERR: " << message << endl; 

但是,我个人更喜欢肯的建议。

+0

+1用于创造性地使用临时生命周期。你能否提供一个'ErrCriticalSectionLocker'的实现,因为语义非常*非平凡? – 2010-12-15 14:55:44

+0

嗯。我懂了;你可以使用这个方法而不用***'括号'***,但是我没有看到这一点,因为我的C(我来自C背景)编程风格通常要求括号。另外,ErrCriticalSectionLocker令人困惑...... – unixman83 2011-07-18 09:00:39

4

这是一个基于线程安全行的日志记录解决方案,我在某个时候制作了。它使用boost mutex来保证线程安全。这是略超过必要的复杂,因为你可以在输出政策塞(它应该去的文件,标准错误,或别的地方?):

logger.h:

#ifndef LOGGER_20080723_H_ 
#define LOGGER_20080723_H_ 

#include <boost/thread/mutex.hpp> 
#include <iostream> 
#include <cassert> 
#include <sstream> 
#include <ctime> 
#include <ostream> 

namespace logger { 
    namespace detail { 

     template<class Ch, class Tr, class A> 
     class no_output { 
     private: 
      struct null_buffer { 
       template<class T> 
       null_buffer &operator<<(const T &) { 
        return *this; 
       } 
      }; 
     public: 
      typedef null_buffer stream_buffer; 

     public: 
      void operator()(const stream_buffer &) { 
      } 
     }; 

     template<class Ch, class Tr, class A> 
     class output_to_clog { 
     public: 
      typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer; 
     public: 
      void operator()(const stream_buffer &s) { 
       static boost::mutex mutex; 
       boost::mutex::scoped_lock lock(mutex); 
       std::clog << now() << ": " << s.str() << std::endl; 
      } 

     private: 
      static std::string now() { 
       char buf[64]; 
       const time_t tm = time(0); 
       strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&tm)); 
       return buf; 
      } 

     }; 

     template<template <class Ch, class Tr, class A> class OutputPolicy, class Ch = char, class Tr = std::char_traits<Ch>, class A = std::allocator<Ch> > 
     class logger { 
      typedef OutputPolicy<Ch, Tr, A> output_policy; 
     public: 
      ~logger() { 
       output_policy()(m_SS); 
      } 
     public: 
      template<class T> 
      logger &operator<<(const T &x) { 
       m_SS << x; 
       return *this; 
      } 
     private: 
      typename output_policy::stream_buffer m_SS; 
     }; 
    } 

    class log : public detail::logger<detail::output_to_clog> { 
    }; 
} 

#endif 

用法如下:

logger::log() << "this is a test" << 1234 << "testing"; 

注缺乏'\n'std::endl因为它是隐含的。内容被缓冲,然后使用模板指定策略以原子方式输出。这个实现也会在行的前面添加一个时间戳,因为它用于记录目的。 no_output策略非常可选,这是我在禁用日志记录时使用的策略。

3

为什么不只是创建一个锁定类,并在任何想要执行线程安全IO的地方使用它?

class LockIO 
{ 
    static pthread_mutex_t *mutex; 
public: 
    LockIO() { pthread_mutex_lock(mutex); } 
    ~LockIO() { pthread_mutex_unlock(mutex); } 
}; 

static pthread_mutex_t* getMutex() 
{ 
    pthread_mutex_t *mutex = new pthread_mutex_t; 
    pthread_mutex_init(mutex, NULL); 
    return mutex; 
} 
pthread_mutex_t* LockIO::mutex = getMutex(); 

然后你把任何IO要在一个块:

std::cout <<"X is " <<x <<std::endl; 

变为:

{ 
    LockIO lock; 
    std::cout <<"X is " <<x <<std::endl; 
}