Нужно знать, как проверить, завершилась ли введенная строка в поточно-безопасном логгере в C ++ - PullRequest
2 голосов
/ 26 августа 2010

Я очень новичок в этом и прошу прощения, если мой вопрос не ясен.

Я создал потокобезопасный регистратор в C ++. Этот регистратор будет использоваться в большой программе и будет вызываться из нескольких мест. Я использую синглтон, так что есть только один экземпляр регистратора. Этот логгер выводит в файл & на консоль. Он ведет себя подобно куту; он принимает строку из другого файла (объединяет ее, если необходимо), сохраняет кусочки в буфере до тех пор, пока строка не будет завершена, а затем выводит с использованием cout. Строка сохраняется как const char *. Прямо сейчас мьютексы заблокированы в одной функции и разблокированы в другой функции (это была моя проблема), которая перегружает оператор endl.

Моя проблема в том, что эта функция (где мьютексы разблокированы) работает только в том случае, если пользователь записывает endl в другие файлы, где вызывается регистратор. Мне нужно, чтобы это была универсальная утилита, которая НЕ будет полагаться на то, что пишет пользователь, поскольку пользователь может не использовать endl или может использовать его слишком часто. Теперь мне нужны некоторые средства для моего регистратора, чтобы определить, когда строка (из другого файла) сделана, чтобы он мог очистить буфер. В настоящее время endl похож на ключевое слово, и мне нужны некоторые средства, чтобы оно работало без каких-либо ключевых слов.

Сначала я думал, что смогу найти какой-нибудь способ проверить завершающий символ "\ 0" в строке, затем использовать эту проверку, чтобы узнать, что строка выполнена, и затем очистить буфер. Однако, когда я делаю это, я выхожу за пределы ошибки.

Спасибо, что уделили время

Ответы [ 3 ]

4 голосов
/ 26 августа 2010

Я не совсем уверен, что понял ситуацию, но звучит так, будто вам нужен прокси:

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

Теперь блокировки не получаются, пока буфер не будет готов к выводу.

0 голосов
/ 26 августа 2010

Проверить https://web.archive.org/web/1/http://articles.techrepublic%2ecom%2ecom/5100-10878_11-5072104.html

Идея заключается в создании локальных потоков "прокси", которые будут вызывать фактическую функцию ведения журнала в потоке.

0 голосов
/ 26 августа 2010

Обычно плохая идея иметь блокировку мьютекса в одной функции и разблокировать в другой.Он должен быть заблокирован и разблокирован в той же функции.

Я создал нечто подобное, и обычно я создал класс C ++ с именем Error.

Таким образом, пользователь создает объект Error и эту ошибкуобъект обрабатывает все вещи завершения.Затем объект ошибки отправляется в очередь ErrorLogger, и журнал ошибок завершается, когда очередь ErrorLogger пуста.Тогда вам не нужно беспокоиться о мьютексах, потому что ErrorLogger успевает обработать из очереди.

...