6000 строк с макросами и шаблонами… и его я должен заинклюдить в каждом своем translation unit…
Вероятно, многие из хедеров которые вы используете даже больше, а, кроме того, 6000 строк будет только один раз при первом вхождении, разве нет?
И еще я пока не понял по API, можно ли как-то динамически изменить уровень вывода в лог?
Да, можно.
Во-первых в командной строке (но это без динамики, только при старте), ну и во-вторых на лету тоже:
Скрытый текст
int main(int argv, char* argc[])
{
/* Копия конфигурации по умолчанию */
el::Configurations defaultConf;
/* Изменим в ней флаг для вывода инфо сообщений */
defaultConf.set(el::Level::Info,
el::ConfigurationType::Enabled, "false");
/* Применим к логгеру по умолчанию */
el::Loggers::reconfigureLogger("default", defaultConf);
LOG(INFO)<<"Не будет выведено";
LOG(WARNING)<<"Будет выведено";
return 0;
}
Вот здесь написано отчасти про их внутреннее устройство и про решение ABA проблемы, кстати тоже. Только вот момент насчёт выигранных четырех бит, как-то не до конца понятен…
Извините за этот наш косяк…
Сначала всё было нормально, но потом поспешили исправить то, о чем говорил lek, и насмешили накосячили.
Спасибо за вашу внимательность.
Мы, вот, всё пытаемся воспроизвести ваш сценарий — пока безуспешно… но попутно кое-что заметили плохое ))
После замечаний от lek, из конструктора шаблона, который здесь на странице пропал вызов InitializeSListHead, в архиве с изначальной версией такой проблемы нет. А отсутствие инициализации головы, как раз, приводит к падению на пустом стеке. (Сейчас исправили здесь в статье)
Результаты работы теста c mutex при малом числе потоков действительно удивляют: даже на этих грубых числах уже видно, что числа с mutex, как минимум сравнимы, а то и меньше, чем у lock-free.
А, вот, насчет 10 мс рассогласования на старте вы совершенно правы, и об этом мы написали чуть выше. Можно было бы избежать этого, например, изменив внешний цикл на do-while, чтобы потребители сразу пробовали брать задания.
Однако, этот фрагмент кода, касается лишь самого теста. Нигде в тексте статьи мы не апеллируем к абсолютным числам по тестам. Проводится лишь сравнение реализаций. А поскольку каждый из 3(4) тестов имеет эти 10 мс, и время работы 1 теста составляет ~10-40 секунд, то они в этом плане абсолютно сравнимы и отмена 10мс не изменит соотношения.
Это совсем не верно. Посмотрите, пожалуйста, на код функции run_test.
1. Стартуют все производители и начинают накидывать задания
2. Стартуют все потребители и уже начинают потреблять задания
3. Ждем окончания работы производителей
4. Ждем окончания работы работы потребителей
Задержка между (1) и (2) только на время запуска (!) потоков, но никак не их работу. Лучше бы было только стартовать каждый из типов попеременно, но это не даст никакой заметной разницы.
Тогда каждый поток должен знать об общем количестве потоков каждого типа, значит ему это нужно давать в аргументе. Это меняет структуру организации worker потоков. Лучше ли это?
И главное для чего? Избежать 1 Wait-а на поток? Общее заданий >>>> числа потоков и один wait на поток ничего не стоит, потому что мы можем потерять на нём 1 раз 10 мс, и то без нагрузки на CPU — это же не sleep…
А это невозможно, потому что hEvtDone ставится после выхода их блокирующего вызова producer_threads.join_all() в методе run_test. Это гарантирует окончание работы всех производителей до того, как consumer-ы пройдут Wait на событии и приступят к своим вторым циклам по чистке стека.
Кажется, что предложенный вами критерий «локальный счетчик количества извлеченных элементов ==iterations» насильственно закрепощает потоки потребители обрабатывать ровно столько заданий, сколько вбросил побратим-производитель в случае p=c, а если p!=c, то это вообще неверно. Так выходит?
И, кроме того, дело-то в том, что исходно обсчитывался квадрат {p X c}, где p почти везде не равно c, так что случай p=c, как бы вырожденный.
Если возникает «ситуация, когда евент сработал, и элементов к тому времени уже нет.», то ничего страшного не будет — это значит, что consumer-ы уже всё разобрали и условие во втором цикле consumer «while (stack.pop(value))» нас тут же выбросит на конец потока. На самом деле, это как раз неплохой сценарий: в том смысле что consumer-ы быстро справились и не надо чистить
Нужен критерий остановки для потребителей. Само по себе отсутствие заданий в стеке не означает, что их больше не будет, т.к. вероятно какие-то производители просто запаздывают и положат задания позднее. Поэтому сначала мы ждем пока все производители отработают и до тех пор честно пробуем найти еще задания в стеке, а вот когда они закончили работу, тогда пустой стек можно считать концом.
Часто проблемы с переносом на Windows бывают, например, c pthread. Хотя есть пару реализаций под WinAPI, но выглядят они как-то не очень.
А так, некоторые вещи из posix поддерживаются в VS SDK, поэтому малая часть проблем с переносом уходит. Вот здесь у них, например, гид по переносу на Win32
А вообще, то что называется кросс-платформенным решением часто не является таковым в полной мере, потому что именно Windows и не поддерживается… И не потому что это невозможно портировать. Так что, скорее, это правильно называть кросс-nix-овые продукты.
А вот многие вещи от Гугла или тот же SQLite, как раз, в большей степени кросс-платформенные: собираются на чём хочешь.
Вероятно, многие из хедеров которые вы используете даже больше, а, кроме того, 6000 строк будет только один раз при первом вхождении, разве нет?
Да, можно.
Во-первых в командной строке (но это без динамики, только при старте), ну и во-вторых на лету тоже:
В плане кода с вашей стороны почти никакой разницы: что типа макросов SYSLOG(LEVEL) вместо LOG(LEVEL)
Сначала всё было нормально, но потом поспешили исправить то, о чем говорил lek, и
насмешилинакосячили.Спасибо за вашу внимательность.
После замечаний от lek, из конструктора шаблона, который здесь на странице пропал вызов InitializeSListHead, в архиве с изначальной версией такой проблемы нет. А отсутствие инициализации головы, как раз, приводит к падению на пустом стеке. (Сейчас исправили здесь в статье)
Вы какой версией пользовались?
У нас вот в таком случае:
ничего не падает
Однако, этот фрагмент кода, касается лишь самого теста. Нигде в тексте статьи мы не апеллируем к абсолютным числам по тестам. Проводится лишь сравнение реализаций. А поскольку каждый из 3(4) тестов имеет эти 10 мс, и время работы 1 теста составляет ~10-40 секунд, то они в этом плане абсолютно сравнимы и отмена 10мс не изменит соотношения.
1. Стартуют все производители и начинают накидывать задания
2. Стартуют все потребители и уже начинают потреблять задания
3. Ждем окончания работы производителей
4. Ждем окончания работы работы потребителей
Задержка между (1) и (2) только на время запуска (!) потоков, но никак не их работу. Лучше бы было только стартовать каждый из типов попеременно, но это не даст никакой заметной разницы.
И главное для чего? Избежать 1 Wait-а на поток? Общее заданий >>>> числа потоков и один wait на поток ничего не стоит, потому что мы можем потерять на нём 1 раз 10 мс, и то без нагрузки на CPU — это же не sleep…
И, кроме того, дело-то в том, что исходно обсчитывался квадрат {p X c}, где p почти везде не равно c, так что случай p=c, как бы вырожденный.
А так, некоторые вещи из posix поддерживаются в VS SDK, поэтому
малаячасть проблем с переносом уходит. Вот здесь у них, например, гид по переносу на Win32А вообще, то что называется кросс-платформенным решением часто не является таковым в полной мере, потому что именно Windows и не поддерживается… И не потому что это невозможно портировать. Так что, скорее, это правильно называть кросс-nix-овые продукты.
А вот многие вещи от Гугла или тот же SQLite, как раз, в большей степени кросс-платформенные: собираются на чём хочешь.