спиновые замки, не потребляющие 100% ресурсов процессора - PullRequest
0 голосов
/ 28 апреля 2020
#include "boost/smart_ptr/detail/spinlock.hpp"
boost::detail::spinlock lock;
main(){
    std::lock_guard<boost::detail::spinlock> guard(lock);
    while(true)
        {
                i=i+100;
        }
}

Информация о машине:

Процессор (ы): 2

Список онлайн-процессоров: 0,1

Поток на core: 1

Core (s) на сокет: 2

Socket (s): 1

Из приведенного выше кода, когда я запустил:

First instance => потребовалось 100% процессорного времени (согласно топ-команде)

Second instance => потребовалось 97-98%, а сумма этих двух экземпляров показывает примерно 195% -197%

Third instance => потребовалось ~ 47-50%, а сумма этих трех показала близость к 200%, отрегулировав потребление ЦП в первых двух экземплярах.

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

Где я ошибаюсь?

1 Ответ

1 голос
/ 28 апреля 2020

Я думаю, вы неправильно понимаете, что такое спин-блокировка. Это не намного сложнее, чем это:

class SpinLock {
public:
    void lock() {
        while (is_locked) { /*do nothing*/ }
        // ...MAGIC HAPPENS HERE...
        is_locked = true;
    }

    void unlock() {
        is_locked = false;
        // ...SUBTLE magic happens here...
    }

private:
    bool is_locked = false;
};

MAGIC - это код, который использует специальные машинные инструкции *, чтобы гарантировать, что, если более чем один поток «вращается» в while l oop в то же время только один из них сможет увидеть is_locked == false и выйти из l oop, когда какой-то другой поток вызовет функцию unlock().

Мое предположение состояло в том, что, как только спин-блокировка получает процессор ...

В спин-блокировке нет ничего, что могло бы "приобрести" процессор. Это просто код, запускаемый процессором , не отличающийся от любого другого кода в вашей программе. Операционная система (ОС) решает, какой поток и на каком процессоре запускать и когда, и ничто из того, что делает спин-блокировка, не может повлиять на это.

... ЦПУ не вытесняет его.

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

«Preempt» означает, что ОС приостанавливает какой-либо работающий поток и позволяет другому потоку запускать ход. Это может происходить порядка 100 раз в секунду, и обычно ни один из задействованных потоков не знает об этом.

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


The SUBTLE magic в функции unlock() состоит из инструкций по барьеру памяти , которые используются для реализации модели памяти C ++ . Это глубокая тема - слишком глубокая для этого ответа.


* Библиотека операций C ++ Atomi c предоставляет низкоуровневый доступ к этим "специальным" машинным инструкциям.

...