Реализация «легкого» spinlock на атомарных операциях

Решил я тут разобраться с атомарными командами, что это такое, какими они бывают и что делают. В целом если объяснять на пальцах, то атомарные или неделимые операции, как следуют из названия, неделимые. Т.е. команда либо еще не выполнена, либо уже выполнена, мы не сможем застать эту операцию в середине процесса. Естественно это реализуется за счет аппаратной поддержке. И у разных архитектур эти команды могут и отличаются, но что бы с вами не зарывались в спецификациях разработчики компиляторов унифицировали работу с этими операциями, описание всех команд можно найти в документации к компилятору(например gcc).

Читая эту документацию и разбираясь с тем как все это работает, мне пришла в голову идея легкого spinlock’a на атомарных функциях. В чем же легкость этого spinlock’a относительного того же mutex’a?! Легкость заключается в том что эта блокировка не приводит к системному вызову, как например блокировка mutex’a.

Итак для создание легкого spinlock’a в userspace нам потребуются 2 функции:

  • bool __atomic_test_and_set (void *ptr, int memorder)
  • void __atomic_clear (bool *ptr, int memorder)

__atomic_test_and_set — устанавливает байт *ptr в некое предопределенное значение ‘set’. Функция вернет true только в том случае если байт *ptr до этого уже находился в состояние ‘set’, иначе функция вернет false. Функцию стоит использовать только с типами char и bool, иначе *ptr будем модифицировано только частично.

__atomic_clear — функция сбрасывает байт *ptr в 0.

int memorder переменная обозначающая используемый способ упорядочения памяти. Это отдельная, довольно обширная тема барьеров памяти разбирать которую в рамках этой статьи я не буду, нам вполне значение по умолчанию __ATOMIC_SEQ_CST, самый строгий ordering. Хотя, если я правильно понял принципы memory ordering’a, то можно использовать более оптимальный Acquire/Release memory ordering.

Теперь сами функции:

 

void spinlock_lock(bool *lock)
{
    /*
     * Крутимся в цикле(spinlock же) пока функция не вернет false,
     * что будет означать что мы захватили блокировку
     */
    while(__atomic_test_and_set(lock, __ATOMIC_SEQ_CST) != false);
}

void spinlock_unlock(bool * lock)
{
    __atomic_clear(lock, __ATOMIC_SEQ_CST);
}

 

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

dreamway89

dreamway89 wrote 29 posts

Post navigation


Comments

  • Bumba

    Удали стастью, это же бред. Учи матчасть

    • dreamway89

      Было бы хорошо получить более развернутый комментарий, ведь если ошибка столь очевидна, ее совсем не сложно описать, да?

Добавить комментарий

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>