2

我对此很陌生,如果我的问题不清楚,我深表歉意。

我在 C++ 中创建了一个线程安全的记录器。该记录器将用于大型程序并从多个地方调用。我使用的是单例,所以只有一个记录器实例。此记录器输出到文件和控制台。它的行为类似于 cout;它从另一个文件中获取一个字符串,(必要时将其连接起来),将这些片段存储在缓冲区中,直到字符串完成,然后使用 cout 输出。该字符串被存储为 const char*。现在,互斥锁被锁定在一个函数中并在另一个函数中解锁(这是我的问题),这会使 endl 运算符重载。

我的问题是这个函数(互斥锁被解锁)只有当用户在调用记录器的其他文件中写入 endl 时才有效。我需要这是一个多功能的实用程序,它不会依赖于用户编写的内容,因为用户可能不使用 endl 或可能过于频繁地使用它。我现在需要一些方法让我的记录器识别字符串(来自另一个文件)何时完成,以便它可以清空缓冲区。目前 endl 就像一个关键字,我需要一些方法让它在没有任何关键字的情况下工作。

我最初认为我可以找到一些方法来检查字符串中的“\0”终止字符,然后使用该检查来知道字符串是否已完成,然后清空缓冲区。但是,当我这样做时,我会出错。

感谢您的时间

4

3 回答 3

4

我不太确定我是否了解情况,但听起来你想要一个代理:

class LogSingleton
{
public:
    LogSingleton& instance() { /* ... */ }

    void lock(); // lock mutex
    void unlock(); // unlock mutex

    template <typename T>
    friend LogSingleton& operator<<(LogSingleton& pLog, const T& pX)
    {
        // needs to be locked first
        assert(is_locked()); 

        /* output pX however */

        return pLog;
    }
};

class LogProxy
{
public:
    LogProxy()
    {
        // manage lock in proxy
        LogSingleton::instance().lock();            
    }

    ~LogProxy()
    {
        LogSingleton::instance().unlock();            
    }
};

// forward input into the proxy to the log, knowing it's locked
template <typename T>
LogProxy& operator<<(LogProxy& pProxy, const T& pX)
{
    LogSingleton::instance() << pX;

    return pProxy;
}

// now expose proxy
typedef LogProxy log;

你会这样做:

log() << "its locked now" << "and the temporary will die" << "here ->";

加锁在构造函数和析构函数中完成,最后调用析构函数。


正如托尼正确指出的那样,这会使锁定时间过长。只有“最终”输出到LogSingleton. 想象一下:

log() << "this next function takes 5 minutes"
        << my_utterly_crappy_function() << "ouch";

什么都没有记录,但互斥锁被锁定了很长时间。更好的是缓冲输出然后一次性输出:

class LogProxy
{
public:
    ~LogProxy()
    {
        // manage lock in proxy
        LogSingleton::instance().lock();

        // no-throw, or wrap mutex use in a scoped-lock
        LogSingleton::instance() << mBuffer.rdbuf();

        LogSingleton::instance().unlock();            
    }

    // buffer output
    template <typename T>
    friend LogProxy& operator<<(LogProxy& pProxy, const T& pX)
    {
        mBuffer << pX;

        return pProxy;
    }

private:
    std::ostringstream mBuffer;
};

现在在缓冲区准备好输出之前不会获取锁。

于 2010-08-25T20:44:01.577 回答
0

通常,在一个函数中使用互斥锁并在另一个函数中解锁是个坏主意。它应该在同一功能中锁定和解锁。

我创建了类似的东西,通常我创建了一个名为 Error 的 C++ 类。

这样,用户创建了一个错误对象,该错误对象处理所有终止内容。然后错误对象被发送到 ErrorLogger 的队列,当 ErrorLogger 队列为空时,错误记录器终止。那你就不用担心互斥量了,因为ErrorLogger有时间处理出队列。

于 2010-08-25T20:36:55.300 回答
0

检查 https://web.archive.org/web/1/http://articles.techrepublic%2ecom%2ecom/5100-10878_11-5072104.html

这个想法是创建线程本地“代理”,它将调用实际的线程安全日志记录功能。

于 2010-08-25T20:40:32.127 回答