Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在多线程进程中同步写入日志_C++_Multithreading_Logging_Boost_Boost Mutex - Fatal编程技术网

C++ 在多线程进程中同步写入日志

C++ 在多线程进程中同步写入日志,c++,multithreading,logging,boost,boost-mutex,C++,Multithreading,Logging,Boost,Boost Mutex,我实现了一个记录器,所以它可以像ostream一样使用。 e、 如果有人想写日志,他可以这样做: LOG << "hello world " << 6 << 8.6 << "\n"; 重载操作符()和操作符使用std::mutex并锁定第一次使用operator()或operator你是对的operator第一感觉是,那operator()和operator就在我的头顶上。如果您想让流io操作符保持原样,可以使用某种代理对象来锁定\解锁互斥体 请

我实现了一个记录器,所以它可以像ostream一样使用。 e、 如果有人想写日志,他可以这样做:

LOG << "hello world " << 6 << 8.6 << "\n";

重载操作符()和操作符使用
std::mutex
并锁定第一次使用
operator()
operator你是对的
operator第一感觉是,那
operator()
operator就在我的头顶上。如果您想让流io操作符保持原样,可以使用某种代理对象来锁定\解锁互斥体

请不要把注意力放在编码风格上(尤其是swfull和危险的日志程序实现)。下面你可以找到上述想法的简要说明

template<class TLogger, class TLockObject>
class LoggerProxy
{
public:
    LoggerProxy(TLogger &logger, TLockObject &lockObj)
        : m_logger(logger),
        m_lockGuard(lockObj)
    {
    }

    template <typename T>
    inline LoggerProxy& operator << (const T& msg)
    {
        m_logger.Write(msg);
        return *this;
    }

private:
    TLogger & m_logger;
    std::lock_guard<typename TLockObject> m_lockGuard;
};

//Purpose of code below is just an illustration of usage LoggerProxy class. Don't use it in production code.
class Logger
{
public:
    static Logger& GetInstance()
    {
        static Logger instance;
        return instance;
    }
    static std::mutex& GetLockObject()
    {
        static std::mutex lockObj;
        return lockObj;
    }

    template <typename T>
    inline void Write (const T& msg) {
        std::cout << msg << std::endl;
    }
};

#define LOG LoggerProxy<Logger, std::mutex>(Logger::GetInstance(), Logger::GetLockObject())

int main()
{

    LOG << 10 << "HELLO" << 1.1;
    LOG << 101 << "HELLO2" << 11.1;

    return 0;
}
模板
类LoggerProxy
{
公众:
LoggerProxy(TLogger和logger、TLockObject和lockObj)
:m_记录器(记录器),
m_锁具(lockObj)
{
}
模板
内联LoggerProxy和运算符共享更少,锁定更少


如果您要在每个
操作符上同步,如果您总是通过同一个“父”函数调用其他两个函数,那么互斥锁怎么会没有帮助呢?将解决您的问题。有什么问题“操作符当然我可以在不同的方法中使用互斥体,但它无法实现我想要的目标。假设我有一个线程调用:LOG,如果你能容忍部分
write()
。使用低级C风格IO来
open())
使用
O_APPEND
创建日志文件,将所有单个日志条目合并到单个C
char
缓冲区,并通过调用
write()
将缓冲区写入日志文件。部分
write()的几率
一个文件非常非常小,它只是一个日志文件。如果用户代码以意外的顺序调用没有
\n
的方法,那么很好地解决了死锁问题!如果您使用这种记录器,您只需提供某种日志输入完成指示。如果用户没有编写结束指示,则进程将挂起!一点也不知道!请记住,任何应用程序都可以有多个互斥体,通过函数调用记录某些内容始终是死日志的起点。这根本不是一个有效的解决方案!唯一的解决方案是在linebreak之前执行本地缓冲区当前项。OP没有指定如何处理此问题。正如我在上面所写的-of co当然,我可以在不同的方法中使用互斥体,但它不会达到我想要的目标。假设我有一个线程来调用:LOG Added of the code sampleBrilliant!我需要在LoggerProxy上指定我的记录器(您模板化的),因为我需要额外的数据(日志级别、文件等)。但是它简单而聪明!谢谢。
template <typename T>
inline Logger& operator << (const T& msg) {
    std::stringstream ss;
    ss << msg;
    PrintToFile(ss.str());
    PrintToScreen(ss.str());
    return *this;
}

Logger& Logger::operator () (const std::string& sourceFile, const std::string& funcName, int lineNumber) {
    std::stringstream ss;
    ss << Utilities::GetFormattedTime("%d.%m.%y %H:%M:%S") << "::" << sourceFile << "(" << lineNumber << ")::" <<
            funcName << "::";
    PrintToFile(level, ss.str());
    PrintToScreen(level, ss.str());
    return *this;
}
class Logger {
     std::mutex mux;
     //...
   public:
     Logger& operator()(/*...*/) {
       mux.lock();
       // write to log
     }
     Logger& operator<<(const string& str) {
       // write to log
       if(str[str.size()-1] == '\n')
         mux.unlock();
     }
     //...
   }; 
template<class TLogger, class TLockObject>
class LoggerProxy
{
public:
    LoggerProxy(TLogger &logger, TLockObject &lockObj)
        : m_logger(logger),
        m_lockGuard(lockObj)
    {
    }

    template <typename T>
    inline LoggerProxy& operator << (const T& msg)
    {
        m_logger.Write(msg);
        return *this;
    }

private:
    TLogger & m_logger;
    std::lock_guard<typename TLockObject> m_lockGuard;
};

//Purpose of code below is just an illustration of usage LoggerProxy class. Don't use it in production code.
class Logger
{
public:
    static Logger& GetInstance()
    {
        static Logger instance;
        return instance;
    }
    static std::mutex& GetLockObject()
    {
        static std::mutex lockObj;
        return lockObj;
    }

    template <typename T>
    inline void Write (const T& msg) {
        std::cout << msg << std::endl;
    }
};

#define LOG LoggerProxy<Logger, std::mutex>(Logger::GetInstance(), Logger::GetLockObject())

int main()
{

    LOG << 10 << "HELLO" << 1.1;
    LOG << 101 << "HELLO2" << 11.1;

    return 0;
}
namespace Logging {

    struct SinkConcept { void commit(std::string const&); }; // documentation only
// movable log transaction (using arbitrary sink)
template <typename Sink> struct LogTx {
    LogTx(Sink& s) : _sink(s) {}
    LogTx(LogTx&&) = default;

    unique_flag        _armed;
    std::ostringstream _oss;
    Sink& _sink;

    ~LogTx() { if (_armed) _sink.commit(_oss.str()); }

    template <typename T> LogTx& operator<<(T&& rhs)&  { return (_oss << rhs), *this; }
    template <typename T> LogTx  operator<<(T&& rhs)&& { return (_oss << rhs), std::move(*this); }
};
struct NullSink { void commit(std::string const&) const {} };
template <typename Impl, bool Flush = true>
struct StreamSink {
    StreamSink(Impl stream_or_ref = {}) : _sor(std::move(stream_or_ref)) {}
    StreamSink(StreamSink&& rhs) : StreamSink(std::move(rhs._sor)) {}

    void commit(std::string const& msg) {
        std::lock_guard<std::mutex> lk(_mx);
        get() << msg << "\n";
        if (Flush) get() << std::flush;
    }

    std::ostream& get() { return _sor; }
  private:
    mutable std::mutex _mx;
    Impl _sor; // stream convertible to ostream&
};
template <typename A, typename B> struct TeeSink { // dispatch to two sinks
    A a; B b;
    void commit(std::string const& msg) { a.commit(msg); b.commit(msg); }
};
// factory functions (mostly not needed in c++17 with deduction guides)
template <typename A, typename B> 
TeeSink<A, B> tee(A&& a, B&& b) { return { std::forward<A>(a), std::forward<B>(b) }; }

StreamSink<std::ofstream, false> log_to(std::ofstream&& file) { return {std::move(file)}; }
StreamSink<std::reference_wrapper<std::ostream>, true> log_to(std::ostream& os) { return {os}; }
auto& log_to_stderr() {
    static StreamSink<std::reference_wrapper<std::ostream>, true> s_instance { log_to(std::cerr) };
    return s_instance;
}
auto& log_to_stdout() {
    static StreamSink<std::reference_wrapper<std::ostream>, true> s_instance { log_to(std::cout) };
    return s_instance;
}
auto& null_sink() {
    static NullSink const s_instance{};
    return s_instance;
}

template <typename Sink>
LogTx<Sink> make_tx(Sink& sink) { return {sink}; }
template <typename Sink>
LogTx<Sink> make_tx(Sink& sink) { return {sink}; }
#define LOG_TO(sink) (Logging::make_tx(sink) << __FILE__ << ":" << __LINE__ << "\t" << __func__ << "\t")
#ifdef NOLOGGING
    #define LOG LOG_TO(Logging::null_sink())
#else
    static auto _file_sink = Logging::log_to(std::ofstream("demo.log"));
    static auto _both_sink = tee(_file_sink, Logging::log_to_stderr());
    #define LOG LOG_TO(_both_sink)
#endif
#include <thread>
void worker(std::string id) {
    while (auto r = rand()%10) {
        std::this_thread::sleep_for(std::chrono::milliseconds(r));
        LOG << "Ping from " << id;
    }
}

int main() {
    LOG << "Hello";
    {
        std::thread a(worker, "A"), b(worker, "B");
        a.join();
        b.join();
    }
    LOG << "Bye";
}
main.cpp:104    main    Hello
main.cpp:99 worker  Ping from A
main.cpp:99 worker  Ping from B
main.cpp:99 worker  Ping from A
main.cpp:99 worker  Ping from B
main.cpp:99 worker  Ping from A
main.cpp:99 worker  Ping from B
main.cpp:99 worker  Ping from B
main.cpp:99 worker  Ping from A
main.cpp:99 worker  Ping from A
main.cpp:99 worker  Ping from A
main.cpp:99 worker  Ping from B
main.cpp:99 worker  Ping from A
main.cpp:99 worker  Ping from A
main.cpp:99 worker  Ping from A
main.cpp:99 worker  Ping from A
main.cpp:110    main    Bye
#include <functional> // for std::reference_wrapper
#include <iostream>
#include <sstream>
#include <fstream>
#include <mutex>

namespace Logging {

    // utility to safely implement movable log transactions
    struct unique_flag {
        bool value = true;
        unique_flag() = default;
        unique_flag(unique_flag&& rhs) : value(rhs.value) { rhs.value = false; }
        operator bool() const { return value; }
    };

    struct SinkConcept { void commit(std::string const&); }; // documentation only

    // movable log transaction (using arbitrary sink)
    template <typename Sink> struct LogTx {
        LogTx(Sink& s) : _sink(s) {}
        LogTx(LogTx&&) = default;

        unique_flag        _armed;
        std::ostringstream _oss;
        Sink& _sink;

        ~LogTx() { if (_armed) _sink.commit(_oss.str()); }

        template <typename T> LogTx& operator<<(T&& rhs)&  { return (_oss << rhs), *this; }
        template <typename T> LogTx  operator<<(T&& rhs)&& { return (_oss << rhs), std::move(*this); }
    };

    // Some sink models
    struct NullSink { void commit(std::string const&) const {} };

    template <typename Impl, bool Flush = true>
    struct StreamSink {
        StreamSink(Impl stream_or_ref = {}) : _sor(std::move(stream_or_ref)) {}
        StreamSink(StreamSink&& rhs) : StreamSink(std::move(rhs._sor)) {}

        void commit(std::string const& msg) {
            std::lock_guard<std::mutex> lk(_mx);
            get() << std::move(msg);
            if (Flush) 
                get() << std::endl;
            else
                get() << "\n";
        }

        std::ostream& get() { return _sor; }
      private:
        mutable std::mutex _mx;
        Impl _sor; // stream convertible to ostream&
    };

    template <typename A, typename B> struct TeeSink { // dispatch to two sinks
        A a; B b;
        void commit(std::string const& msg) { a.commit(msg); b.commit(msg); }
    };

    // factory functions (mostly not needed in c++17 with deduction guides)
    template <typename A, typename B> 
    TeeSink<A, B> tee(A&& a, B&& b) { return { std::forward<A>(a), std::forward<B>(b) }; }

    StreamSink<std::ofstream, false> log_to(std::ofstream&& file) { return {std::move(file)}; }
    StreamSink<std::reference_wrapper<std::ostream>, true> log_to(std::ostream& os) { return {os}; }

    StreamSink<std::reference_wrapper<std::ostream>, true>& log_to_stderr() {
        static StreamSink<std::reference_wrapper<std::ostream>, true> s_instance { log_to(std::cerr) };
        return s_instance;
    }
    StreamSink<std::reference_wrapper<std::ostream>, true>& log_to_stdout() {
        static StreamSink<std::reference_wrapper<std::ostream>, true> s_instance { log_to(std::cout) };
        return s_instance;
    }
    NullSink const& null_sink() {
        static NullSink const s_instance{};
        return s_instance;
    }

    template <typename Sink>
    LogTx<Sink> make_tx(Sink& sink) { return {sink}; }
}

#define LOG_TO(sink) (Logging::make_tx(sink) << __FILE__ << ":" << __LINE__ << "\t" << __func__ << "\t")
#ifdef NOLOGGING
    #define LOG      LOG_TO(Logging::null_sink())
#else
    static auto _file_sink = Logging::log_to(std::ofstream("demo.log"));
    static auto _both_sink = tee(_file_sink, Logging::log_to_stderr());
    #define LOG      LOG_TO(_both_sink)
#endif

#include <thread>
void worker(std::string id) {
    while (auto r = rand()%10) {
        std::this_thread::sleep_for(std::chrono::milliseconds(r));
        LOG << "Ping from " << id;
    }
}

int main() {
    LOG << "Hello";
    {
        std::thread a(worker, "A"), b(worker, "B");
        a.join();
        b.join();
    }
    LOG << "Bye";
}