开发者

Need to know how to check if the inputted string has terminated within a thread-safe logger in C++

开发者 https://www.devze.com 2023-01-13 17:12 出处:网络
I am very new at this and apolo开发者_JS百科gise if my question is not clear. I have created a thread safe logger in C++. This logger will be used in a large program & will be called from multipl

I am very new at this and apolo开发者_JS百科gise if my question is not clear.

I have created a thread safe logger in C++. This logger will be used in a large program & will be called from multiple places. I am using a singleton so there is only one instance of the logger. This logger outputs to a file & to the console. It behaves similar to cout; it takes in a string from another file, ( concatenates it if necessary), stores the peices in a buffer until the string is done then outputs using cout. The string is being stored as a const char*. Right now the mutexes are being locked in one function and unlocked in another function ( this is were my problem is) which overloads the endl operator.

My problem is that this function (where the mutexes are unlocked )only works if the user writes endl in the other files where the logger is being called. I need this to be a versatile utility which will NOT rely on what the user writes since a user may not use endl or may use it too often. I now need some means for my logger to identify when the string ( from the other file) is done so that it can empty out the buffer. Currently endl is like a keyword & i need some means to make it work without any key words.

I was initially thinking i could find some means to check for the "\0" terminating character in the string then using that check to know that the string is done and then emptying out the buffer. However, i get out of bounds errors when i do this.

Thank you for your time


I'm not quite sure I get the situation, but it sounds like you want a proxy:

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;

And you'd do this:

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

The locking is done in the constructor and destructor, and the destructor is called at the end.


As Tony correctly points out, this holds the lock unnecessarily long. The lock is only needed for the "final" output to the LogSingleton. Imagine this:

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

Nothings getting logged yet the mutex is locked for a long time. Better would be to buffer-up output then output it all at once:

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;
};

Now no locks are acquired until the buffer is ready to be outputted.


Typically it's a bad idea to have mutex lock in one function and unlock in another. It should be locked and unlocked in the same function.

I created something similar, and typically I made a C++ class called Error.

That way the user creates an Error object, and that error object handles all the termination stuff. Then the error object gets sent to the ErrorLogger's Queue, and the error logger terminates when the ErrorLogger Queue is empty. Then you don't have to worry about mutexes, because the ErrorLogger has time to process out of the queue.


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

The idea is to create thread-local "proxies" which will call actual thread-safe logging function.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号