AHTOXA 15 1 ноября, 2018 Опубликовано 1 ноября, 2018 · Жалоба По месту, думаю, должен использоваться класс-счётчик, типа TickCounter<T>. У него внутри уже будет спрятана вся эта магия. А снаружи - инкремент и чтение. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 56 1 ноября, 2018 Опубликовано 1 ноября, 2018 · Жалоба 8 минут назад, AHTOXA сказал: По месту, думаю, должен использоваться класс-счётчик, типа TickCounter<T>. У него внутри уже будет спрятана вся эта магия. А снаружи - инкремент и чтение. Не понял. Вот берём пример из стартового поста: INLINE tick_count_t get_tick_count() { TCritSect cs; return Kernel.SysTickCount; } Тут TCritSect разворачивается в полноценный код. Но мы-то этого не хотим, например, в случае арма, где доступ к SysTickCount и так атомарный. Как сделать так, чтобы на арме секция была пустой, а на авре полной? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 1 ноября, 2018 Опубликовано 1 ноября, 2018 · Жалоба Здесь будет так: INLINE tick_count_t get_tick_count() { return Kernel.SysTickCounter.get(); } А уже унутре этого get() будет вся магия. То есть, в TKernel вместо tick_count_t SysTickCount будет TickCounter<tick_count_t> SysTickCounter; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 1 ноября, 2018 Опубликовано 1 ноября, 2018 · Жалоба 14 hours ago, AHTOXA said: Если используется #include <type_traits> и auto, то это уже c++11. А если можно c++11, то незачем городить эти шаблоны вручную, там есть std::conditional. Нету. Точнее, есть, но не работает, как хочется. Передать в конструктор экземпляр переменной, чтобы он сам догадался, какой у неё тип, можно только в C++17 (вчера узнал новое слово). А объявлять критическую секцию не для переменной, а для класса этой переменной (или decltype писать) мне не понравилось. 14 hours ago, AHTOXA said: Что там сейчас используется от с++11? std::is_arithmetic и std::is_enum. Думаю, можно обойтись без. Это я делал, чтобы случайно не зацепить какой-то класс с небольшим количеством переменных. Но можно понадеяться на сознательность программиста, тем более это решение и так имеет много ограничений. 5 hours ago, dxp said: И ещё не очень понятно, как это по месту использовать, чтобы автоматом оно понимало что с чем сравнивать. Тут самая главная проблема, что эта "критическая" секция ограничивается только чтением и записью. В остальных случаях атомарность НЕ гарантируется. Пожалуй лучше даже назвать в духе CritSectionReadWrite. 1 hour ago, AHTOXA said: По месту, думаю, должен использоваться класс-счётчик, типа TickCounter<T>. У него внутри уже будет спрятана вся эта магия. Тут я согласен с Сергеем, что изначальная идея касалась только счётчика времени, но может свободно распространиться и на остальные переменные ядра. А тут-то всё и ломается - во-первых, их больше одной, а во-вторых, начинают массово плодиться вложенные крит.секции. Можно сделать, чтобы оно и так работало, но от изначальной идеи - "проще и быстрее" ничего не останется... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 1 ноября, 2018 Опубликовано 1 ноября, 2018 · Жалоба Я не очень понял, почему будут вложенные критические секции. Скажем, сейчас у нас есть в TEventFlag переменная volatile TValue Value; а будет volatile AtomicReadWrite<TValue> Value; Соответственно, все места, где были чтения с созданием критических секций, заменятся на Value.read(), а места, где были места с записью - на Value.set(). Для пущей гибкости можно добавить функции для чтения-записи без критических секций (безусловно), и наоборот, с обязательным созданием крит. секции. Получится уже вполне гибкий класс, который можно применить во многих местах. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 56 1 ноября, 2018 Опубликовано 1 ноября, 2018 · Жалоба Т.е. если в коде есть два обращения к двум разным переменным, объявленным таким способом, то для каждой будет рожаться критическая секция вместо того, чтобы использовать одну на обе? Например, вот простейший флаг события: bool OS::TEventFlag::wait(timeout_t timeout) { TCritSect cs; if(Value) // if flag already signaled { Value = efOff; // clear flag return true; } else { cur_proc_timeout() = timeout; suspend(ProcessMap); if(is_timeouted(ProcessMap)) return false; // waked up by timeout or by externals cur_proc_timeout() = 0; return true; // otherwise waked up by signal() or signal_isr() } } Тут секция защищает всю функцию. Как тут эта автоматика поможет? Тут же несколько разных объектов и вызов внутренних функций, которые подразумевают, что вызываются из критической секции (а внутри они тоже выполняют немало действий, которые должны производиться тоже в критической секции). Проводить анализ, что там безопасно, а что опасно без критической секции, это ещё та работа. Сейчас оно просто и серьмяжно лочит на входе, и всё работает как часы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 1 ноября, 2018 Опубликовано 1 ноября, 2018 · Жалоба В таких местах использовать функции чтения/записи, которые без критической секции. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 56 1 ноября, 2018 Опубликовано 1 ноября, 2018 · Жалоба Ну, так а профит-то получается в чём? Кроме этой get_tick_count() что-то больше и мест не особо просматривается. А там получается вместо одного макроса целая плюсовая кухня вырисовывается. И с чем боремся? :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 1 ноября, 2018 Опубликовано 1 ноября, 2018 · Жалоба Ну, лично я сразу принял вариант с макросом:) А Сергей сказал, что надо что-то универсальнее. Вот и придумываем:)) Вот, я имел в виду что-то типа такого: template <typename T, size_t atomicSize = 4> class AtomicVar { public: void set(T value) { CS cs; val = value; } void setForceCs(T value) { TCritSect cs; val = value; } void setNoCs(T value) { val = value; } T get() { CS cs; return val; } T getNoCs() { return val; } T getForceCs() { TCritSect cs; return val; } void inc(); // -- для тиков private: struct FakeCriticalSection {}; using CS = typename std::conditional<sizeof(T) <= atomicSize, FakeCriticalSection, TCritSect>::type; T val; }; Можно использовать вместо Kernel.SysTickCount, TEventFlag::Value и в других подобных местах. По крайней мере позволит убрать все ненужные критические секции почти автоматом, и не придумывая на каждый случай макрос. ЗЫ. Вот мини-тест: https://wandbox.org/permlink/zmJsh7mWUj1oQ2JH Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 56 1 ноября, 2018 Опубликовано 1 ноября, 2018 · Жалоба 9 минут назад, AHTOXA сказал: Можно использовать вместо Kernel.SysTickCount, TEventFlag::Value и в других подобных местах. По крайней мере позволит убрать все ненужные критические секции почти автоматом, и не придумывая на каждый случай макрос. Код красивый, и что он эффективно работает, не сомневаюсь. Но обращаюсь опять к прежнему своему вопросу: вот код функции TEventFlag::wait, там есть ветка else, она тоже защищена критической секцией. Как этот красивый шаблон поможет защитить код в else? Этот шаблон хорошо подходит только для одиночных переменных. Что собственно и отражено в его имени. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 1 ноября, 2018 Опубликовано 1 ноября, 2018 · Жалоба Я ведь уже ответил на этот твой вопрос:) В TEventFlag::wait() нужно оставить общую критическую секцию и использовать функции без CS (getNoCs()/setNoCs()). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 56 1 ноября, 2018 Опубликовано 1 ноября, 2018 · Жалоба Ну, т.е. по сути не менять в этом случае ничего? И какой тогда смысл менять TValue на AtomicVar<TValue>? Получается, что конкретно класс TEventFlag трогать вообще смысла нет. Я правильно понимаю? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 1 ноября, 2018 Опубликовано 1 ноября, 2018 · Жалоба Ну почему же. В TEventFlag уберутся критические секции в функциях clear() и is_signaled(). Полной автоматизации не выйдет, но небольшой кусочек будет оптимальнее. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 56 1 ноября, 2018 Опубликовано 1 ноября, 2018 · Жалоба Ну, если уж на то пошло, то конкретно в этом классе TValue - это тип, который на практике всегда атомарный (перечисление с двумя значениями). Даже любой 8-битник может работать с этим за одно обращение. Получается, что из этих функций критическую секцию можно вообще убрать без ущерба для безопасности. Так что таки флаг событий не видится претендентом для использования в нём красивого шаблона. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 1 ноября, 2018 Опубликовано 1 ноября, 2018 · Жалоба Наверняка у Сергея есть ещё кандидаты на оптимизацию. Давай подождём, что он скажет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться