Перейти к содержанию
    

По месту, думаю, должен использоваться класс-счётчик, типа TickCounter<T>. У него внутри уже будет спрятана вся эта магия. А снаружи - инкремент и чтение.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 минут назад, AHTOXA сказал:

По месту, думаю, должен использоваться класс-счётчик, типа TickCounter<T>. У него внутри уже будет спрятана вся эта магия. А снаружи - инкремент и чтение.

Не понял. Вот берём пример из стартового поста:
 

   INLINE tick_count_t get_tick_count() { TCritSect cs; return Kernel.SysTickCount; }

Тут TCritSect разворачивается в полноценный код. Но мы-то этого не хотим, например, в случае арма, где доступ к SysTickCount и так атомарный. Как сделать так, чтобы на арме секция была пустой, а на авре полной?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Здесь будет так:

   INLINE tick_count_t get_tick_count() { return Kernel.SysTickCounter.get(); }

А уже унутре этого get() будет вся магия.

То есть, в TKernel вместо tick_count_t SysTickCount будет TickCounter<tick_count_t> SysTickCounter;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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>. У него внутри уже будет спрятана вся эта магия.

Тут я согласен с Сергеем, что изначальная идея касалась только счётчика времени, но может свободно распространиться и на остальные переменные ядра. А тут-то всё и ломается - во-первых, их больше одной, а во-вторых, начинают массово плодиться вложенные крит.секции. Можно сделать, чтобы оно и так работало, но от изначальной идеи - "проще и быстрее" ничего не останется...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я не очень понял, почему будут вложенные критические секции. Скажем, сейчас у нас есть в TEventFlag переменная

        volatile TValue      Value;


а будет

        volatile AtomicReadWrite<TValue>      Value;



Соответственно, все места, где были чтения с созданием критических секций, заменятся на Value.read(), а места, где были места с записью - на Value.set().

Для пущей гибкости можно добавить функции для чтения-записи без критических секций (безусловно), и наоборот, с обязательным созданием крит. секции. Получится уже вполне гибкий класс, который можно применить во многих местах.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Т.е. если в коде есть два обращения к двум разным переменным, объявленным таким способом, то для каждой будет рожаться критическая секция вместо того, чтобы использовать одну на обе? Например, вот простейший флаг события:

 

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()
    }
}

Тут секция защищает всю функцию. Как тут эта автоматика поможет? Тут же несколько разных объектов и вызов внутренних функций, которые подразумевают, что вызываются из критической секции (а внутри они тоже выполняют немало действий, которые должны производиться тоже в критической секции). Проводить анализ, что там безопасно, а что опасно без критической секции, это ещё та работа. Сейчас оно просто и серьмяжно лочит на входе, и всё работает как часы. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В таких местах использовать функции чтения/записи, которые без критической секции.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну, так а профит-то получается в чём? Кроме этой get_tick_count() что-то больше и мест не особо просматривается. А там получается вместо одного макроса целая плюсовая кухня вырисовывается. И с чем боремся? :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну, лично я сразу принял вариант с макросом:)
А Сергей сказал, что надо что-то универсальнее. Вот и придумываем:))
Вот, я имел в виду что-то типа такого:
 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 минут назад, AHTOXA сказал:

Можно использовать вместо Kernel.SysTickCount, TEventFlag::Value и в других подобных местах. По крайней мере позволит убрать все ненужные критические секции почти автоматом, и не придумывая на каждый случай макрос.

Код красивый, и что он эффективно работает, не сомневаюсь. Но обращаюсь опять к прежнему своему вопросу: вот код функции TEventFlag::wait, там есть ветка else, она тоже защищена критической секцией. Как этот красивый шаблон поможет защитить код в else? Этот шаблон хорошо подходит только для одиночных переменных. Что собственно и отражено в его имени. :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я ведь уже ответил на этот твой вопрос:)
В TEventFlag::wait() нужно оставить общую критическую секцию и использовать функции без CS (getNoCs()/setNoCs()).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну, т.е. по сути не менять в этом случае ничего? И какой тогда смысл менять TValue на AtomicVar<TValue>? Получается, что конкретно класс TEventFlag трогать вообще смысла нет. Я правильно понимаю?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну почему же. В TEventFlag уберутся критические секции в функциях clear() и is_signaled(). Полной автоматизации не выйдет, но небольшой кусочек будет оптимальнее.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну, если уж на то пошло, то конкретно в этом классе TValue - это тип, который на практике всегда атомарный (перечисление с двумя значениями). Даже любой 8-битник может работать с этим за одно обращение. Получается, что из этих функций критическую секцию можно вообще убрать без ущерба для безопасности. Так что таки флаг событий не видится претендентом для использования в нём красивого шаблона. :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Наверняка у Сергея есть ещё кандидаты на оптимизацию. Давай подождём, что он скажет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...