Довольно ужасный код, голова болит от него… Микс разных подходов, проблемы с синхронизацией, видна попытка сделать асинхронный логгер, но жёсткий мьютекс закрывающий запись логов всё равно делает всё по сути последовательным… 😖
Нарисуйте на листочке временную диаграмму процессов, чтобы представить что с чем должно работать параллельно. Вполне может быть, что асинхронность даже и не нужна будет…
Да, наверно, можно считать и так. Сейчас читаю Уильямса, «Паралельное программирование на С++» и пробую применить прочитанное. Вот и интересно мнение людей, более знающих, чем я.
if (m_messages.size() > m_limit) m_cond_var.notify_one();
notify_one нужно вызывать с уже разблокированным мьютексом.
cpp.reference.com:
When a lock_guard object is created, it attempts to take ownership of the mutex it is given. When control leaves the scope in which the lock_guard object was created, the lock_guard is destructed and the mutex is released.
Как его разблокировать? Что-то вроде
{
lock_guard<mutex> lock(m_mut);
push_back(_msg);
}
if (m_messages.size() > m_limit) m_cond_var.notify_one();
Предлагаю get_logger() переделать на синглтон Майерса и переименовать в get_instance().
Название get_instance() намекнет пользователю что класс синглтон.
Check the condition, in case it was already updated and notified \
Call wait, wait_for, or wait_until on the std::condition_variable (atomically releases the mutex and suspends thread execution until the condition variable is notified, a timeout expires, or a spurious wakeup occurs, then atomically acquires the mutex before returning) \
Check the condition and resume waiting if not satisfied
or:
Use the predicated overload of wait, wait_for, and wait_until, which performs the same three steps
Вам мало того что уже написали? Если Вас интересует конкретно мой input - имеем дело с кучей лишних телодвижений, ненужных mallocs и (что более важно) - syscall’ами, и безосновательно длинными критическими секциями. Не так обычно логеры пишут, совсем не так.
Предлагаю get_logger() переделать на синглтон Майерса
Настоятельно рекомендую хотя бы одним глазком посмотреть в какой asm это развернётся. Один «лишний» conditional jump в предложенном решении - way better. Ну, и при желании, даже его можно было бы избежать.
Добавил конструктору тельце чтобы линкер не ругался. https://godbolt.org/z/sv1hKhdMj
Посмотрел еще раз. Добавился код для конструктора и гарды чтобы вызов instance() был потокобезопасным. Вас гарды смущают?
Да, смущают. Пипец как смущают. Это call, и в лучшем случае лишние atomics. Там где пары инструкций должно было хватить. Но, возможно, у Вас другие критерии. И вообще - я попИсать вышел.
Мой Вам совет: начните изучение сразу с lock-free алгоритмов, да и вообще темы неблокирукирующей синхронизации. Один раз сломаете мозг об неё, зато потом, понимание взаимодействий потоков не будет вызывать никаких сложностей.
Не надо писать «using std» и снимать квалификацию.
Не надо писать std::string, а написать разок навроде
using logString = std::string
и использовать потом везде алиас logString.
Понатыкивать везде длинные квалификации навроде std::tratata::trututu… - это моветон. это плохо читается и лишний раз подчеркивает ненужные особенности расположения каких-то обьектов, до которой вашей программе дела нет.
Ваша программа должна выглядеть как код общего вида, для решения некоей конкретной задачи, а не как вариант виртуозного использования(есть такие мастера) плюсовых либ и стандартов в вашем случае.
Представьте, что программу придется перенести на другой язык. и представьте обьем работы по выскребанию оттуда всей этой тряхомудии.
Используйте алиасы и отвязывайтесть от библиотечной плюсовой конкретики.
Пишите код так, чтобы его мог кто-то другой прочитать. Пишите его не для себя, а для читателя(это вообще заповедь номер один). не ставьте читателю капканы, в которые он попадет.
Часто говорят, что с++ - сложный язык… но это впечатление во многом связано с тем, что люди пишут простые вещи слишком сложно и слишком прибито к стандртным либам.
Плохо писать глобальные переменные без static, или анонимного неймспейса, поскольку читателю кажется, это переменная видна в других единицах компиляции.
Плохо использовать константы отличные от тривиальных (типа нуля) в явном виде, надо константы именовать вразумительным образом, а потом и подставлять.
Пишите комменты к функциям, отличным от тривиальных, хотя бы краткие. код без комментов - мусорный.
Используйте алиасы и отвязывайтесть от библиотечной плюсовой конкретики.
Хороший совет (нет). Тогда тебя не никогда смогут уволить, потому что никто не сможет понять, что это за MySuperPuperString и MySuperPuperMap и пара-тройка десятков других алиасов/классов в твоем коде.
что это за MySuperPuperString и MySuperPuperMap и пара-тройка десятков других алиасов/классов в твоем коде
нет ниакакой разницы между MySuperPuperString и MySuperPuperClass или MySuperPuperVar. вы и имена не будете давать классам и переменным? это же опасно, не так ли.
алиас в данном случае - просто новое имя класса. и если вы уже научились давать классам вразумительные имена, примените это навык и к алиасам.
зы. а если вдруг понадобится вариант кода для std::wstring или вроде того… вы что будете делать-то? копипейстить и править на новый тип, или просто измените алиас? код такого рода уж точно не должен зависеть от представления строк.
нет ниакакой разницы между MySuperPuperString и MySuperPuperClass или MySuperPuperVar.
Конечно, есть разница. Когда я вижу std::string, я точно знаю, что я могу с ним делать, где посмотреть документацию, и т.д. А когда я вижу твой logString, я не знаю ничего. Более того, если у тебя в одной части кода logString, а в другой какой-нибудь тип webString, то хрен его знает, один ли и тот же это тип или разные, и как мне передать logString туда, где хотят webString. Это называется каша.
Причем, в языках, отличных от С++, такая хрень не распространена. Везде используются стандартные типы. И правильно делают, зачем изобретать свою кривую систему базовых типов? Но почему-то в С++ как нагородят-нагородят, а потом еще и жалуются, какой мол С++ корявый язык.
Когда я вижу std::string, я точно знаю, что я могу с ним делать
аргумент вида - когда я вижу int я точно знаю что с ним делать. потому кроме int, других типов не нужно.
Более того, если у тебя в одной части кода logString, а в другой какой-нибудь тип webString, то хрен его знает,…
если типы разные - значит скорее всего они разные не просто так. а преобразование типов описывается в рамках с++.
Везде используются стандартные типы. И правильно делают, зачем изобретать свою кривую систему базовых типов?
открой фреймфорк QT, и посмотри сколько там своих «базовых типов» включая QString. и откуда следует, что std:: типы - «прямые»? для нормальной работы их обычно надо допиливать до вменяемого состояния.
фреймворки наоборот любят запилить свои типы, чтобы отвязаться от хотелок комитета по стандартизации с++.
А теперь - внимание, вопрос! Если мы договорились что такой singleton имеет noticeable overhead - зачем в принципе его (overhead) изначально приносить и потом с ним бороться?
А теперь - внимание, вопрос! Если мы договорились что такой singleton имеет noticeable overhead - зачем в принципе его (overhead) изначально приносить и потом с ним бороться?
синглетоны сделанные в виде локальных статиков обеспечивают корректную инициализацию обьектов в общем виде. и по другому ее не сделать, а можно сделать только ручками. но за это надо платить дополнительной булевской переменной и гардом типа мьютекса, поскольку неинициализированный статик могут сразу запросить несколько тредов и тут нужна синхронизация.
в данном случае такие синглетоны - плата за отсутствие модулей в плюсах.
можно сделать и ручками глобальную инициализацию, но это чревато.
открой фреймфорк QT, и посмотри сколько там своих «базовых типов»
Ололо, отличная идея отсылать к фреймворку, базовые названия и стайлгайды которого формировались когда в стандарте не было половины текущего функционала. Да, откройте сорцы Qt и посмотрите, какой там повсюду говнокод. Его только-только начали причесывать, но все бесконечные ни с чем не совместимые QString и QByteArray никуда не денутся.
хотелок комитета по стандартизации с++.
Опять злые капиталисты в штаны насрали, ведь в комитете сидят идиоты, а автор выше лучше них знает, как надо писать на С++
Где я написал, что «Qt говно, а вот ххх - заебись?». Qt - говно, потому что полон легаси, которое писалось в допотопные времена. Ни больше, ни меньше. И относиться к нему как к «эталону продуманности» глупо.
STL - не фреймворк, а библиотека шаблонов. или по вашему STL закрывает тему фреймворков и все кроме stl должно быть выброшено в мусорку, поскольку этой самой STL теперь хватит на все случаи жизни?
вы настаиваете, что алиасы типов не нужны в принципе, одновременно утверждая, что в комитете по с++ собрались умные головы? так они алиасы и вводили.
пишите, как угодно, строго на STL, если вам этого хватает, вряд ли кто будет тут возражать