Реализация критического раздела - PullRequest
0 голосов
/ 30 января 2012

Как лучше и быстрее создать критический раздел?

С двоичным семафором, между sem_wait и sem_post.
Или с атомарными операциями:

#include <sched.h>

void critical_code(){
    static volatile bool lock = false;

    //Enter critical section
    while ( !__sync_bool_compare_and_swap (&lock, false, true ) ){
        sched_yield();
    }

    //...

    //Leave critical section
    lock = false;
}

Ответы [ 4 ]

3 голосов
/ 30 января 2012

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

С учетом вышесказанного, нет никаких оснований для того, чтобы закатывать такие собственные спин-блокировки. Либо используйте pthread_spin_lock, если вы хотите спин-блокировку, либо pthread_mutex_lock или sem_wait (с двоичным семафором), если вы хотите блокировку, которая может уступать другим процессам, когда они утверждаются. Код, который вы написали, является худшим из обоих миров по тому, как он использует sched_yield. Вызов sched_yield гарантирует, что блокировка будет ждать не менее нескольких миллисекунд (и, вероятно, весь временной интервал планирования) в случае, когда есть конфликт блокировки и нагрузка на процессор, и она будет сжигать 100% ЦП, когда есть конфликт, но нет ЦП. нагрузка (например, из-за блокировки замка в IO). Если вы хотите получить какое-либо из преимуществ спин-блокировки, вам нужно вращаться без каких-либо системных вызовов. Если вы хотите получить какое-либо преимущество от использования процессора, вы должны использовать правильный примитив синхронизации, который будет использовать (в Linux) futex (или эквивалентные) операции для получения точно до тех пор, пока блокировка не станет доступной - не короче и не больше.

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

2 голосов
/ 30 января 2012

Вы недостаточно глубоко изучили документацию по gcc. Правильные встроенные функции для такого типа блокировки: __sync_lock_test_and_set и __sync_lock_release. У них есть именно те гарантии, которые вам нужны для такой вещи. С точки зрения нового стандарта C11 это будет тип atomic_flag с операциями atomic_flag_test_and_set и atomic_flag_clear.

Как уже указывает Р., помещать sched_yield в цикл - действительно плохая идея.

Если код внутри критической секции состоит только из нескольких циклов, вероятность того, что его выполнение пересекает границу среза планирования, мала. Количество потоков, которые будут заблокированы, активно вращающихся, будет не более числа процессоров минус один. Все это не работает, если вы уступите выполнение, как только не получите блокировку немедленно. Если у вас есть реальная конкуренция за блокировку и yield, у вас будет множество контекстных переключателей, которые приведут вашу систему почти в режим ожидания.

2 голосов
/ 30 января 2012

Спин-блокировки работают лучше, если для блокировки мало конкуренции и / или она никогда не удерживается в течение длительного периода времени.В противном случае вам лучше иметь блокировку, которая блокирует, а не вращает.Конечно, есть гибридные блокировки, которые будут вращаться несколько раз, и если блокировка не может быть получена, они будут блокироваться.

Что лучше для вас, зависит от вашего приложения.Только вы можете ответить на этот вопрос.

0 голосов
/ 08 февраля 2012

Как уже указывали другие, на самом деле не совсем важно, насколько быстрым является код блокировки.Это связано с тем, что, как только последовательность блокировки инициируется с помощью «xchg reg, mem», сигнал блокировки отправляется через кэш-память на устройства на всех шинах.Когда последнее устройство подтвердило, что оно будет удерживать и подтвердило это - что может занять сотни, если не тысячу тактов, выполняется фактический обмен.Если ваше самое медленное устройство - это классическая PCI-карта, она будет иметь скорость шины 33 МГц, что составляет около одной сотой внутренней тактовой частоты процессора.И устройству PCI (если оно активно) потребуется несколько тактов (@ 33 МГц) для ответа.В течение этого времени центральный процессор будет ожидать возвращения подтверждения.

Большинство спин-блокировок, вероятно, используются в драйверах устройств, где процедура не будет прервана операционной системой, но может быть прервана более высокимдрайвер уровня.

Критическая секция - это на самом деле просто спин-блокировка, но с интерфейсом для ОС, поскольку она может быть прервана.

...