3

std::cerr行単位でスレッドセーフになるように独自のものを作成する最も簡単な方法は何ですか。

私はできればそれを行うためのコードを探しています。

私が必要とするのは、あるスレッドによって生成されたa line of output(で終了する)が、コンソールで実際に表示されたときに残るようにすることです (そして、他のスレッドの出力と混合されません)。std::endlas a line of output


解決策: cstdio よりもはるかに遅いstd::cerrです私は、コンストラクターがスレッドセーフなロックを取得し、デストラクターがそれを解放するクラスfprintf(stderr, "The message")内で使用することを好みます。CriticalSectionLocker

4

5 に答える 5

3

これは、ある時点で作成したスレッドセーフな行ベースのロギングソリューションです。スレッドセーフのためにブーストミューテックスを使用します。出力ポリシーをプラグインできるため、必要以上に少し複雑です (ファイル、stderr、または他の場所に移動する必要がありますか?)。

ロガー.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";

andは暗黙的であるため、 '\n'andがないことに注意してください。std::endlコンテンツはバッファリングされ、テンプレートで指定されたポリシーを使用してアトミックに出力されます。この実装では、ロギング目的であるため、行の前にタイムスタンプも追加されます。ポリシーは完全にオプションです。no_outputロギングを無効にするときに使用します。

于 2010-12-15T22:08:28.660 に答える
2

ロッククラスを作成して、スレッドセーフな 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;
}
于 2013-03-06T00:19:41.427 に答える
2

これ:

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

の一般的なケースでは、ほとんどのコンパイラで動作しmyerr("ERR: " << message << number)ます。

于 2010-12-15T05:01:14.977 に答える
1

unixman のコメントでのアプローチの改善 (コメントには収まりません)。

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

次のように使用できます

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

ErrCriticalSectionLocker が慎重に実装されている場合。

しかし、私は個人的にケンの提案を好む.

于 2010-12-15T06:45:04.717 に答える