AHTOXA 3 November 1, 2018 Posted November 1, 2018 · Report post По месту, думаю, должен использоваться класс-счётчик, типа TickCounter<T>. У него внутри уже будет спрятана вся эта магия. А снаружи - инкремент и чтение. Quote Share this post Link to post Share on other sites More sharing options...
dxp 29 November 1, 2018 Posted November 1, 2018 · Report post 8 минут назад, AHTOXA сказал: По месту, думаю, должен использоваться класс-счётчик, типа TickCounter<T>. У него внутри уже будет спрятана вся эта магия. А снаружи - инкремент и чтение. Не понял. Вот берём пример из стартового поста: INLINE tick_count_t get_tick_count() { TCritSect cs; return Kernel.SysTickCount; } Тут TCritSect разворачивается в полноценный код. Но мы-то этого не хотим, например, в случае арма, где доступ к SysTickCount и так атомарный. Как сделать так, чтобы на арме секция была пустой, а на авре полной? Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 3 November 1, 2018 Posted November 1, 2018 · Report post Здесь будет так: INLINE tick_count_t get_tick_count() { return Kernel.SysTickCounter.get(); } А уже унутре этого get() будет вся магия. То есть, в TKernel вместо tick_count_t SysTickCount будет TickCounter<tick_count_t> SysTickCounter; Quote Share this post Link to post Share on other sites More sharing options...
esaulenka 0 November 1, 2018 Posted November 1, 2018 · Report post 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>. У него внутри уже будет спрятана вся эта магия. Тут я согласен с Сергеем, что изначальная идея касалась только счётчика времени, но может свободно распространиться и на остальные переменные ядра. А тут-то всё и ломается - во-первых, их больше одной, а во-вторых, начинают массово плодиться вложенные крит.секции. Можно сделать, чтобы оно и так работало, но от изначальной идеи - "проще и быстрее" ничего не останется... Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 3 November 1, 2018 Posted November 1, 2018 · Report post Я не очень понял, почему будут вложенные критические секции. Скажем, сейчас у нас есть в TEventFlag переменная volatile TValue Value; а будет volatile AtomicReadWrite<TValue> Value; Соответственно, все места, где были чтения с созданием критических секций, заменятся на Value.read(), а места, где были места с записью - на Value.set(). Для пущей гибкости можно добавить функции для чтения-записи без критических секций (безусловно), и наоборот, с обязательным созданием крит. секции. Получится уже вполне гибкий класс, который можно применить во многих местах. Quote Share this post Link to post Share on other sites More sharing options...
dxp 29 November 1, 2018 Posted November 1, 2018 · Report post Т.е. если в коде есть два обращения к двум разным переменным, объявленным таким способом, то для каждой будет рожаться критическая секция вместо того, чтобы использовать одну на обе? Например, вот простейший флаг события: 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() } } Тут секция защищает всю функцию. Как тут эта автоматика поможет? Тут же несколько разных объектов и вызов внутренних функций, которые подразумевают, что вызываются из критической секции (а внутри они тоже выполняют немало действий, которые должны производиться тоже в критической секции). Проводить анализ, что там безопасно, а что опасно без критической секции, это ещё та работа. Сейчас оно просто и серьмяжно лочит на входе, и всё работает как часы. Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 3 November 1, 2018 Posted November 1, 2018 · Report post В таких местах использовать функции чтения/записи, которые без критической секции. Quote Share this post Link to post Share on other sites More sharing options...
dxp 29 November 1, 2018 Posted November 1, 2018 · Report post Ну, так а профит-то получается в чём? Кроме этой get_tick_count() что-то больше и мест не особо просматривается. А там получается вместо одного макроса целая плюсовая кухня вырисовывается. И с чем боремся? :) Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 3 November 1, 2018 Posted November 1, 2018 · Report post Ну, лично я сразу принял вариант с макросом:) А Сергей сказал, что надо что-то универсальнее. Вот и придумываем:)) Вот, я имел в виду что-то типа такого: 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 Quote Share this post Link to post Share on other sites More sharing options...
dxp 29 November 1, 2018 Posted November 1, 2018 · Report post 9 минут назад, AHTOXA сказал: Можно использовать вместо Kernel.SysTickCount, TEventFlag::Value и в других подобных местах. По крайней мере позволит убрать все ненужные критические секции почти автоматом, и не придумывая на каждый случай макрос. Код красивый, и что он эффективно работает, не сомневаюсь. Но обращаюсь опять к прежнему своему вопросу: вот код функции TEventFlag::wait, там есть ветка else, она тоже защищена критической секцией. Как этот красивый шаблон поможет защитить код в else? Этот шаблон хорошо подходит только для одиночных переменных. Что собственно и отражено в его имени. :) Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 3 November 1, 2018 Posted November 1, 2018 · Report post Я ведь уже ответил на этот твой вопрос:) В TEventFlag::wait() нужно оставить общую критическую секцию и использовать функции без CS (getNoCs()/setNoCs()). Quote Share this post Link to post Share on other sites More sharing options...
dxp 29 November 1, 2018 Posted November 1, 2018 · Report post Ну, т.е. по сути не менять в этом случае ничего? И какой тогда смысл менять TValue на AtomicVar<TValue>? Получается, что конкретно класс TEventFlag трогать вообще смысла нет. Я правильно понимаю? Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 3 November 1, 2018 Posted November 1, 2018 · Report post Ну почему же. В TEventFlag уберутся критические секции в функциях clear() и is_signaled(). Полной автоматизации не выйдет, но небольшой кусочек будет оптимальнее. Quote Share this post Link to post Share on other sites More sharing options...
dxp 29 November 1, 2018 Posted November 1, 2018 · Report post Ну, если уж на то пошло, то конкретно в этом классе TValue - это тип, который на практике всегда атомарный (перечисление с двумя значениями). Даже любой 8-битник может работать с этим за одно обращение. Получается, что из этих функций критическую секцию можно вообще убрать без ущерба для безопасности. Так что таки флаг событий не видится претендентом для использования в нём красивого шаблона. :) Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 3 November 1, 2018 Posted November 1, 2018 · Report post Наверняка у Сергея есть ещё кандидаты на оптимизацию. Давай подождём, что он скажет. Quote Share this post Link to post Share on other sites More sharing options...