Пишу простую велосипедную библиотеку для ведения логов из программы. Она должна уметь писать в один файл из нескольких потоков. Поскольку при добавлении записи в лог туда пишется еще и заголовок, и еще много чего делается, функция записи блокируется:
Хочется теперь добавить возможность вручную получить в клиентском коде блокировку записи в лог на некоторое время, чтобы иметь возможность добавить несколько сообщений, которые гарантированно идут подряд:
Как бы это получше сделать? Очевидный вариант - использовать мьютекс с атрибутом PTHREAD_MUTEX_ERRORCHECK и дополнительный флаг manually_locked, и снимать блокировку, только если этот флаг не установлен. При этом все вызовы pthread_mutex_lock до снятия вручную блокировки будут просто возвращать EDEADLK и все ок. Проблема в том, что такие мьютексы тормозные и непереносимые.
много гемора, придется делать очередь с приоритетами - надо ведь будет отложить сообщения от других потоков, если установлена ручная блокировка. Ну и плюс придется как-то передавать сообщения, а это копирования, динамическое выделение памяти и пр. нехорошие вещи.
не вижу ничего страшного в этом... Кроме того, если чесно, идея сообщений подряд в ЛОГАХ мне совсем не понятна. Введите простое идентифицирующее поле в логе и фильтрация/выборка становится в разы проще :)
Это страшно, если понадобится риалтаймовый лог. Его будет очень проблематично сделать с такой очередью и пересылкой сообщений.
Сообщения подряд я хотел сделать, чтобы, например, при желании можно было спокойно записать большой json-объект, не создавая временные строки и используя стандартные методы.
ну в принципе да ) требования: - потенциальное реальное время (при условии риалтаймого fprintf или его аналогов) - потокобезопасность - простота и малый размер - возможность сборки без pthreads (небезопасная, но все равно должна работать) - (бонус) syslog в качестве бакэнда (на целевой машине его, правда, нет)
а я хз сколько нужно) на самом деле, я почитал, действительно, рекурсивные мьютексы описаны как минимум в 2001 посиксе, так что буду просто использовать их пока что, это проще всего. Не люблю я, правда, их, потому что сломать очень легко. Я видимо попутал их с errorcheck, который пока считается не особо переносимым.
да, будет узкое место. 100500 потоков пока не планируется, их на самом деле чуть меньше десяти. Те, что пишут вместе, могут подождать. Но вот те, что пишут отдельно, ждать не могут вообще. Может и надо было как-нибудь извернуться и сделать хитрую очередь, но я уже потратил почти три дня, и менять это дело столь радикально поздно. Может, в далеком светлом будущем)
При использовании очереди потоки не ждут (почти, зависит от реализации). Ждёт логгер. А последовательная запись, выше уже посоветовали: добавлять в лог название потока, pid, timestamp.
А читать grep pid и вот вся последовательная запись.
да я знаю, что плохо, когда потоки блокируются на всю операцию записи. тут просто дело в том, что мне надо было сделать, чтобы если единственный поток пишет в файл, то это был риалтайм. Я прикинул, и реализация этого дела с сообщениями показалась мне излишен сложной, поэтому решил блокировать. Возможно я ошибся тогда, и сделать это было бы не сложнее того, что есть сейчас. На данный момент у меня 800 строк, и надеюсь больше тысячи не набежит.
Не использовать очерень при записи в лог — нехорошо. Если что-то случится в функции записи в файл, может упасть весь поток (не уверен, что это в с++ легко возможно, но в управляемых языках — более чем).
ну это значит, что максимальное время работы функции log() теоретически можно посчитать. Теоретически - потому что у нас на практике никто этим заниматься не будет).
Я уже понял, что можно организовать очередь сообщений и писать в отдельно потоке, но поздняк - дело сделано, переделывать некогда.