LINUX.ORG.RU

man pthread_mutex_init

или как выше предложили - в job, там любой каприз за ваши деньги

даже по приведённой ссылке неясно что за вопрос. Кроме того что реализация «class Log» пользуется успехом на LOR

MKuznetsov ★★★★★
()

что неправильно, чего не хватает.

Довольно ужасный код, голова болит от него… Микс разных подходов, проблемы с синхронизацией, видна попытка сделать асинхронный логгер, но жёсткий мьютекс закрывающий запись логов всё равно делает всё по сути последовательным… 😖

raspopov
()
Ответ на: комментарий от braboar

Как сделать (правильно) асинхронный логгер?

Нарисуйте на листочке временную диаграмму процессов, чтобы представить что с чем должно работать параллельно. Вполне может быть, что асинхронность даже и не нужна будет…

raspopov
()
Ответ на: комментарий от slovazap

Да, наверно, можно считать и так. Сейчас читаю Уильямса, «Паралельное программирование на С++» и пробую применить прочитанное. Вот и интересно мнение людей, более знающих, чем я.

braboar ★★
() автор топика
  1. if (!m_logger.get()) m_logger.reset(new Logger);

Первый раз вижу, чтобы так делали синглтоны. Гонка потоков.

  1. if (m_messages.size() > m_limit) m_cond_var.notify_one();

notify_one нужно вызывать с уже разблокированным мьютексом.

  1. for (list::const_iterator it = m_messages.begin(); it != m_messages.end(); ++it)

range based for loop

  1. lock_guard lock(m_mut);
  1. unique_lock ul(m_cond_var_mutex);

Два презерватива на всякий пожарный? Зачем столько мьютексов?

  1. m_cond_var.wait_for(ul, chrono::seconds(m_interval));

Без предиката не рекомендуется использовать wait. Потому что может быть ложные пробуждение.

  1. break;
  1. flush_log();

Мёртвый код.

И ещё пару мест, которые мне лень копипастить.


Короче полностью переписать.

ox55ff ★★★★★
()
Ответ на: комментарий от ox55ff

notify_one нужно вызывать с уже разблокированным мьютексом.

Спасибо

Два презерватива на всякий пожарный? Зачем столько мьютексов?

Исправлю.

Без предиката не рекомендуется использовать wait. Потому что может быть ложные пробуждение.

Хорошо, посмотрю.

Спасибо!

braboar ★★
() автор топика
Ответ на: комментарий от ox55ff

Первый раз вижу, чтобы так делали синглтоны. Гонка потоков.

Это как раз абсолютно нормально. Главное дёрнуть разок до того как треды начали форкаться, и потом экономить на синхронизации.

Но согласен - код в оригинальном виде кривенький донельзя. Учится человек пока, это ожидаемо. Могло было быть гораздо хуже.

bugfixer ★★★★★
()
Ответ на: комментарий от bugfixer

Это как раз абсолютно нормально. Главное дёрнуть разок до того как треды начали форкаться, и потом экономить на синхронизации.

Да, этот поток запускается первым.

Но согласен - код в оригинальном виде кривенький донельзя. Учится человек пока, это ожидаемо. Могло было быть гораздо хуже.

Вот еще бы с уточнением рабиуса кривизны, а?

braboar ★★
() автор топика
Ответ на: комментарий от ox55ff
  1. 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();
braboar ★★
() автор топика
Ответ на: комментарий от bugfixer

Главное дёрнуть разок до того как треды начали форкаться

Это знание, явно не выраженное в коде. Забудешь про это требование или другой человек придёт и всё сломается.

ox55ff ★★★★★
()

Для защиты данных и condition_vatiable нужно использовать один mutex.
Лучше использовать condition_vatiable::wait() с предикатом.

https://en.cppreference.com/w/cpp/thread/condition_variable
Any thread that intends to wait on a std::condition_variable must:
Acquire a std::unique_lockstd::mutex on the mutex used to protect the shared variable
Do one of the following:

  1. Check the condition, in case it was already updated and notified \
  2. 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) \
  3. 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

Еще пояснение о том как condition_vatiable использует mutex
https://ru.stackoverflow.com/questions/1279013/condition-variable-c
https://habr.com/ru/post/182626/

imatveev13
()
Ответ на: комментарий от braboar

Вот еще бы с уточнением радиуса кривизны, а?

Вам мало того что уже написали? Если Вас интересует конкретно мой input - имеем дело с кучей лишних телодвижений, ненужных mallocs и (что более важно) - syscall’ами, и безосновательно длинными критическими секциями. Не так обычно логеры пишут, совсем не так.

bugfixer ★★★★★
()
Последнее исправление: bugfixer (всего исправлений: 1)
Ответ на: комментарий от imatveev13

Предлагаю get_logger() переделать на синглтон Майерса

Настоятельно рекомендую хотя бы одним глазком посмотреть в какой asm это развернётся. Один «лишний» conditional jump в предложенном решении - way better. Ну, и при желании, даже его можно было бы избежать.

bugfixer ★★★★★
()

Mutex’сы - как их правильно готовить

  • спрашиваешь свободен ли mutex
    • ждёшь
      • захватываешь mutex
        • захватываешь данные на которое он «наложен»
          • теперь все ждут тебя
            • отдаёшь mutex
              • теперь mutex захвачен другим
                • делаешь свои дела дальше и если снова нужны данные
                  • спрашиваешь свободен ли mutex
                    • ждёшь

И так по кругу до сегфолта :D

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от bugfixer

Добавил конструктору тельце чтобы линкер не ругался.
https://godbolt.org/z/sv1hKhdMj
Посмотрел еще раз. Добавился код для конструктора и гарды чтобы вызов instance() был потокобезопасным. Вас гарды смущают?

imatveev13
()
Ответ на: комментарий от imatveev13

Вас гарды смущают?

Да, смущают. Пипец как смущают. Это call, и в лучшем случае лишние atomics. Там где пары инструкций должно было хватить. Но, возможно, у Вас другие критерии. И вообще - я попИсать вышел.

bugfixer ★★★★★
()

Мой Вам совет: начните изучение сразу с lock-free алгоритмов, да и вообще темы неблокирукирующей синхронизации. Один раз сломаете мозг об неё, зато потом, понимание взаимодействий потоков не будет вызывать никаких сложностей.

QsUPt7S ★★
()
Ответ на: комментарий от menangen

Так дай ссылки что почитать в PDF.

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

Я начинал знакомство с серии статей «Lock-free структуры данных». В этой серии, кстати, приводится много ссылок на другие источники.
Про протоколы когерентности кешей есть хорошая статья «Принципы работы кэш-памяти».
Для первичного ознакомления с терминологией стоит прочитать вот это «Akka Documentation: Terminology, Concepts».
Обязательно к прочтению классика от Лесли Лэмпорта: «Time, Clocks, and the Ordering of Events in a Distributed System» и «How to Make a Multiprocessor Computer That Correctly Executes Multiprocess Programs». Остальные его работы смотрите в списке его публикаций.
Начать знакомство с самими lock-free структурами данных стоит со Стека Трайбера и Очереди Майкла и Скотта.
Продолжите знакомством с алгоритмом LCRQ Адама Моррисона. Остальные его публикации. После знакомства с LCRQ, возможно Вы, как и многие до Вас, переизобретёте колесо алгоритм FAA Array Queue. Ваш покорный слуга тоже не избежал этой участи…
Кроме того, советую заглянуть на страничку публикаций Майкла Ли Скотта, там можно найти много интересного. Например продвинутый вариант алгоритма LCRQ - алгоритм MPDQ. На основе этого алгоритма можно улучшить и FAA Array Queue.

QsUPt7S ★★
()
Последнее исправление: QsUPt7S (всего исправлений: 1)

Не надо писать «using std» и снимать квалификацию.

Не надо писать std::string, а написать разок навроде

using logString = std::string

и использовать потом везде алиас logString.

Понатыкивать везде длинные квалификации навроде std::tratata::trututu… - это моветон. это плохо читается и лишний раз подчеркивает ненужные особенности расположения каких-то обьектов, до которой вашей программе дела нет.

Ваша программа должна выглядеть как код общего вида, для решения некоей конкретной задачи, а не как вариант виртуозного использования(есть такие мастера) плюсовых либ и стандартов в вашем случае.

Представьте, что программу придется перенести на другой язык. и представьте обьем работы по выскребанию оттуда всей этой тряхомудии.

Используйте алиасы и отвязывайтесть от библиотечной плюсовой конкретики.

Пишите код так, чтобы его мог кто-то другой прочитать. Пишите его не для себя, а для читателя(это вообще заповедь номер один). не ставьте читателю капканы, в которые он попадет.

Часто говорят, что с++ - сложный язык… но это впечатление во многом связано с тем, что люди пишут простые вещи слишком сложно и слишком прибито к стандртным либам.

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

Плохо использовать константы отличные от тривиальных (типа нуля) в явном виде, надо константы именовать вразумительным образом, а потом и подставлять.

Пишите комменты к функциям, отличным от тривиальных, хотя бы краткие. код без комментов - мусорный.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

и использовать потом везде алиас logString.

Используйте алиасы и отвязывайтесть от библиотечной плюсовой конкретики.

Хороший совет (нет). Тогда тебя не никогда смогут уволить, потому что никто не сможет понять, что это за MySuperPuperString и MySuperPuperMap и пара-тройка десятков других алиасов/классов в твоем коде.

rupert ★★★★★
()
Ответ на: комментарий от rupert

что это за MySuperPuperString и MySuperPuperMap и пара-тройка десятков других алиасов/классов в твоем коде

нет ниакакой разницы между MySuperPuperString и MySuperPuperClass или MySuperPuperVar. вы и имена не будете давать классам и переменным? это же опасно, не так ли.

алиас в данном случае - просто новое имя класса. и если вы уже научились давать классам вразумительные имена, примените это навык и к алиасам.

зы. а если вдруг понадобится вариант кода для std::wstring или вроде того… вы что будете делать-то? копипейстить и править на новый тип, или просто измените алиас? код такого рода уж точно не должен зависеть от представления строк.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

нет ниакакой разницы между MySuperPuperString и MySuperPuperClass или MySuperPuperVar.

Конечно, есть разница. Когда я вижу std::string, я точно знаю, что я могу с ним делать, где посмотреть документацию, и т.д. А когда я вижу твой logString, я не знаю ничего. Более того, если у тебя в одной части кода logString, а в другой какой-нибудь тип webString, то хрен его знает, один ли и тот же это тип или разные, и как мне передать logString туда, где хотят webString. Это называется каша.

Причем, в языках, отличных от С++, такая хрень не распространена. Везде используются стандартные типы. И правильно делают, зачем изобретать свою кривую систему базовых типов? Но почему-то в С++ как нагородят-нагородят, а потом еще и жалуются, какой мол С++ корявый язык.

rupert ★★★★★
()
Ответ на: комментарий от rupert

Когда я вижу std::string, я точно знаю, что я могу с ним делать

аргумент вида - когда я вижу int я точно знаю что с ним делать. потому кроме int, других типов не нужно.

Более того, если у тебя в одной части кода logString, а в другой какой-нибудь тип webString, то хрен его знает,…

если типы разные - значит скорее всего они разные не просто так. а преобразование типов описывается в рамках с++.

Везде используются стандартные типы. И правильно делают, зачем изобретать свою кривую систему базовых типов?

открой фреймфорк QT, и посмотри сколько там своих «базовых типов» включая QString. и откуда следует, что std:: типы - «прямые»? для нормальной работы их обычно надо допиливать до вменяемого состояния. фреймворки наоборот любят запилить свои типы, чтобы отвязаться от хотелок комитета по стандартизации с++.

alysnix ★★★
()
Ответ на: комментарий от bugfixer

Вас гарды смущают?

Да, смущают. Пипец как смущают. Это call, и в лучшем случае лишние atomics.

Согласен, меня тоже смущают. Поэтому использую так:

Singleton *s = Singleton::instance();

for (...)
    s->work();
imatveev13
()
Ответ на: комментарий от imatveev13

Согласен, меня тоже смущают.

А теперь - внимание, вопрос! Если мы договорились что такой singleton имеет noticeable overhead - зачем в принципе его (overhead) изначально приносить и потом с ним бороться?

bugfixer ★★★★★
()
Ответ на: комментарий от imatveev13

А теперь - внимание, вопрос! Если мы договорились что такой singleton имеет noticeable overhead - зачем в принципе его (overhead) изначально приносить и потом с ним бороться?

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

в данном случае такие синглетоны - плата за отсутствие модулей в плюсах.

можно сделать и ручками глобальную инициализацию, но это чревато.

alysnix ★★★
()
Ответ на: комментарий от alysnix

открой фреймфорк QT, и посмотри сколько там своих «базовых типов»

Ололо, отличная идея отсылать к фреймворку, базовые названия и стайлгайды которого формировались когда в стандарте не было половины текущего функционала. Да, откройте сорцы Qt и посмотрите, какой там повсюду говнокод. Его только-только начали причесывать, но все бесконечные ни с чем не совместимые QString и QByteArray никуда не денутся.

хотелок комитета по стандартизации с++.

Опять злые капиталисты в штаны насрали, ведь в комитете сидят идиоты, а автор выше лучше них знает, как надо писать на С++

PPP328 ★★★★★
()
Последнее исправление: PPP328 (всего исправлений: 1)
Ответ на: комментарий от PPP328

Ололо, отличная идея отсылать к фреймворку, базовые названия и стайлгайды которого…

прекрасно. называешь свой любимый нормальный(не забытую поделку пары человек)фреймфорк, и мы смотрим его сорсы и типы.

alysnix ★★★
()
Ответ на: комментарий от alysnix

STL.

Где я написал, что «Qt говно, а вот ххх - заебись?». Qt - говно, потому что полон легаси, которое писалось в допотопные времена. Ни больше, ни меньше. И относиться к нему как к «эталону продуманности» глупо.

PPP328 ★★★★★
()
Ответ на: комментарий от PPP328

STL - не фреймворк, а библиотека шаблонов. или по вашему STL закрывает тему фреймворков и все кроме stl должно быть выброшено в мусорку, поскольку этой самой STL теперь хватит на все случаи жизни?

вы настаиваете, что алиасы типов не нужны в принципе, одновременно утверждая, что в комитете по с++ собрались умные головы? так они алиасы и вводили.

пишите, как угодно, строго на STL, если вам этого хватает, вряд ли кто будет тут возражать

alysnix ★★★
()