Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.71/21: Рейтинг темы: голосов - 21, средняя оценка - 4.71
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607

Spinlock c std::this_thread::yield

01.01.2020, 16:17. Показов 4798. Ответов 30
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день, не могу найти обоснование применения функции "уступить другим потокам" при реализации спинлока, хотя нечто подобное есть в релизации boost::detail::spinlock. Я набрался наглости сделать свою реализацию, потомучто моя интуиция подсказывает что она лучше. Но надо ещё всё это обосновать, а я даже не знаю откуда взять информацию. Собственно надо обосновать что после некоторого количества "долбёжек" уместно сделать паузу, и ещё лучше обосновать предел после которого надо делать паузу. Выбранный предел в 100'000 наверняка неоптимальный.
Или не стоит замарачиваться а взять boost::detail::spinlock, но он нормальный в плане производительности или это просто игрушка детская ?

Вот моя реализация для случая когда спинлок требуется для синглтона:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
class TSpinlock
{
    static std::atomic_bool spin_flag; // noexcept
    static std::atomic_uint mesaured_delay;
public:
    static void  mesaure_spinlockratio()
    {
        try
        {
            using std::this_thread::yield;
            using ratio = std::chrono::nanoseconds;
            using std::chrono::duration_cast;
            using clock = std::chrono::high_resolution_clock;
            unsigned curr_delay = 0;
            auto start = clock::now();
            std::unique_lock<std::mutex> lock(mtxwd);
            lock.unlock();
            auto stop = clock::now();
            auto dur = duration_cast<ratio>(stop - start);
            curr_delay = dur.count();
            std::cout << "mutex delay(nano):" << curr_delay << std::endl;
            bool cond = (curr_delay > (default_delay));
            mesaured_delay =  cond?curr_delay: default_delay;
        }
        catch(...)
        {
            assert("mesaure_spinlockratio");
        }
    }
 
    static void lock() noexcept
    {
        using std::this_thread::yield; // noexcept
        using ratio =std::chrono::nanoseconds;
        using std::chrono::duration_cast;
        using clock = std::chrono::high_resolution_clock;
        constexpr auto max_attempts = 100'000;
        unsigned curr_ratio = 1;
        unsigned timedelay = mesaured_delay.load();
        bool result = false;
        unsigned attempt_number = 0;
        while(!result)
        {
            bool expected = false;
            result = spin_flag.compare_exchange_weak(expected, true); // noexcept
            if (!result)
            {
                attempt_number++;
                if (attempt_number == max_attempts)
                {
                    attempt_number = 0;
                    unsigned curr_delay = 0;
                    auto start = clock::now(); // noexcept
                    do
                    {
                        yield(); // noexcept
                        auto stop = clock::now(); // noexcept
                        // constexpr
                        curr_delay = duration_cast<ratio>(stop - start).count();
                    } while(curr_delay < timedelay);
 
                }
            }
        }
    }
 
    static void unlock() noexcept
    {
        spin_flag.store(false);
    }
};
std::atomic_bool TSpinlock::spin_flag = false; // noexcept
std::atomic_uint TSpinlock::mesaured_delay = default_delay;
Добавлено через 6 минут
Очень много радикальных суждений встречал по поводу спинлока и хочется написать код, который будет воспринят нормально другими разработчиками.

Добавлено через 30 минут
Небольшие огрешности были. Поправил.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
class TSpinlock
{
    static std::atomic_bool spin_flag; // noexcept
    static std::atomic_uint mesaured_delay;
    static std::mutex mtxwd;
    static constexpr unsigned default_delay = 10;  // minumum for spinlock
public:
    static void  mesaure_spinlockratio()
    {
        try
        {
            using std::this_thread::yield;
            using ratio = std::chrono::nanoseconds;
            using std::chrono::duration_cast;
            using clock = std::chrono::high_resolution_clock;
            unsigned curr_delay = 0;
            auto start = clock::now();
            std::unique_lock<std::mutex> lock(mtxwd);
            lock.unlock();
            auto stop = clock::now();
            auto dur = duration_cast<ratio>(stop - start);
            curr_delay = dur.count();
            std::cout << "mutex delay(nano):" << curr_delay << std::endl;
            bool cond = (curr_delay > (default_delay));
            mesaured_delay =  cond?curr_delay: default_delay;
        }
        catch(...)
        {
            assert("mesaure_spinlockratio");
        }
    }
 
    static void lock() noexcept
    {
        using std::this_thread::yield; // noexcept
        using ratio =std::chrono::nanoseconds;
        using std::chrono::duration_cast;
        using clock = std::chrono::high_resolution_clock;
        constexpr auto max_attempts = 100'000;
        unsigned curr_ratio = 1;
        unsigned timedelay = mesaured_delay.load();
        bool result = false;
        unsigned attempt_number = 0;
        while(!result)
        {
            bool expected = false;
            result = spin_flag.compare_exchange_weak(expected, true); // noexcept
            if (!result)
            {
                attempt_number++;
                if (attempt_number == max_attempts)
                {
                    attempt_number = 0;
                    unsigned curr_delay = 0;
                    auto start = clock::now(); // noexcept
                    do
                    {
                        yield(); // noexcept
                        auto stop = clock::now(); // noexcept
                        // constexpr
                        curr_delay = duration_cast<ratio>(stop - start).count();
                    } while(curr_delay < timedelay);
                }
            }
        }
    }
 
    static void unlock() noexcept
    {
        spin_flag.store(false);
    }
};
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
01.01.2020, 16:17
Ответы с готовыми решениями:

С++ memory ordering: fetch_sub(acquire) и spinlock на основе atomic_flag (Энтони Вильямс "Мультитрид в действии")
Читаю Вильямса по мультитриду. 1) В книге приведён пример класса spinlock на основе atomic_flag: class spinlock_mutex{ ...

Не могу разобраться как обновить в std::map<std::string, вектор_структур>
Не могу разобраться как обновить вектор структур после его добавления в map без удаления и перезаписи struct pStruct { int...

std::string, std::fstream, ошибка кучи
где то начало вылетать при операции += с локальной переменной std::string. Заменил на свой qString. Замечательно, то же самое... ошибка при...

30
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
01.01.2020, 18:45
Цитата Сообщение от squareroot Посмотреть сообщение
потомучто моя интуиция подсказывает что она лучше.
лучше чем?

Цитата Сообщение от squareroot Посмотреть сообщение
Или не стоит замарачиваться а взять boost::detail::spinlock, но он нормальный в плане производительности или это просто игрушка детская ?
я так скажу, производительность lock/unlock имеет куда меньше значения, чем то, что находится между ними при использовании.
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
01.01.2020, 19:13  [ТС]
Цитата Сообщение от GbaLog- Посмотреть сообщение
лучше чем?


я так скажу, производительность lock/unlock имеет куда меньше значения, чем то, что находится между ними при использовании.
Я вижу необходимость в собственном спинлоке по нескольким причинам:
1)Неохота всегда и везде цеплять boost, а в стандартной библиотеки его нет
2)В некоторых местах мьютекс не годиться так как нужен код noexcept
Я постарался сделать свою версию очень близко похожею на бустовскую:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
class TSpinlock
{
    static std::atomic_bool spin_flag; // noexcept
    static std::atomic_uint mesaured_delay;
    static std::mutex mtxwd;
    static constexpr unsigned default_delay = 100;  // minumum for spinlock
    TSpinlock() = default;
    TSpinlock(const TSpinlock&) = delete;
    TSpinlock(TSpinlock&&) = delete;
    TSpinlock& operator=(const TSpinlock&) = delete;
    TSpinlock& operator=(TSpinlock&&) = delete;
public:
    static TSpinlock& create_spinlock()
    {
        static TSpinlock slock;
        return slock;
    }
    static void  mesaure_spinlockratio()
    {
        try
        {
            using std::this_thread::yield;
            using ratio = std::chrono::nanoseconds;
            using std::chrono::duration_cast;
            using clock = std::chrono::high_resolution_clock;
            unsigned curr_delay = 0;
            auto start = clock::now();
            std::unique_lock<std::mutex> lock(mtxwd);
            lock.unlock();
            auto stop = clock::now();
            auto dur = duration_cast<ratio>(stop - start);
            curr_delay = dur.count();
            std::cout << "mutex delay(nano):" << curr_delay << std::endl;
            bool cond = (curr_delay > (default_delay));
            mesaured_delay =  cond?curr_delay: default_delay;
        }
        catch(...)
        {
            assert("mesaure_spinlockratio");
        }
    }
 
    static void lock() noexcept
    {
        using std::this_thread::yield; // noexcept
        using ratio =std::chrono::nanoseconds;
        using std::chrono::duration_cast;
        using clock = std::chrono::high_resolution_clock;
        constexpr auto max_attempts = 256;
        unsigned curr_ratio = 1;
        unsigned timedelay = mesaured_delay.load();
        bool result = false;
        unsigned attempt_number = 0;
        while(!result)
        {
            bool expected = false;
            // noexcept
            result = spin_flag.compare_exchange_weak(expected,
                                                     true,
                                                     std::memory_order_acquire);
            if (!result)
            {
                attempt_number++;
                if (attempt_number % 16 == 0) BOOST_SMT_PAUSE
                if (attempt_number == max_attempts)
                {
                    attempt_number = 0;
                    unsigned curr_delay = 0;
                    auto start = clock::now(); // noexcept
                    // ! std::this_thread::sleep_for is not noexcept
                    do
                    {
                        yield(); // noexcept
                        auto stop = clock::now(); // noexcept
                        // constexpr
                        curr_delay = duration_cast<ratio>(stop - start).count();
                    } while(curr_delay < timedelay);
                }
            }
        }
    }
 
    static void unlock() noexcept
    {
        spin_flag.store(false, std::memory_order_release);
    }
};
std::atomic_bool TSpinlock::spin_flag = false; // noexcept
std::atomic_uint TSpinlock::mesaured_delay = default_delay;
TSpinlock& spin = TSpinlock::create_spinlock();
Проблема для меня в том как этот код будет восприниматься другими.
Для некоторых использование

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
                if (attempt_number == max_attempts)
                {
                    attempt_number = 0;
                    unsigned curr_delay = 0;
                    auto start = clock::now(); // noexcept
                    // ! std::this_thread::sleep_for is not noexcept
                    do
                    {
                        yield(); // noexcept
                        auto stop = clock::now(); // noexcept
                        // constexpr
                        curr_delay = duration_cast<ratio>(stop - start).count();
                    } while(curr_delay < timedelay);
                }
Полный треш, особенно yield(), хотя у в бусте вроде тоже нечто похожее.
0
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
01.01.2020, 19:35
Цитата Сообщение от squareroot Посмотреть сообщение
Неохота всегда и везде цеплять boost
ну, чисто теоретически, можно просто вырезать реализацию с std::atomic из буста. она довольно компактная.
https://www.boost.org/doc/libs... atomic.hpp
единственный момент состоит в том, что там используется boost::detail::yield с параметром. но и его реализация достаточно небольшая, так что её можно тоже вырезать без особых усилий.
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
01.01.2020, 19:56  [ТС]
Цитата Сообщение от GbaLog- Посмотреть сообщение
ну, чисто теоретически, можно просто вырезать реализацию с std::atomic из буста. она довольно компактная.
https://www.boost.org/doc/libs... atomic.hpp
единственный момент состоит в том, что там используется boost::detail::yield с параметром. но и его реализация достаточно небольшая, так что её можно тоже вырезать без особых усилий.
Этим не обойдёшься. Там одно тащит за собой другое.
C++
1
2
/* Yield the processor.  */
extern int sched_yield (void) __THROW;
Добавлено через 9 минут
И ещё надо nanosleep, которая совсем не noexcept
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
01.01.2020, 21:42
Думаю лучше все таки уступать дорогу другим потокам вместо того что бы пытаться пробиться к ресурсу долгое время. Вы же не отдельные потоки программируете а саму программу в целом. А много потоков вам судя по всему нужно для ускорения. Так вот, что по вашему будет лучше, если один поток пытается захватить доступ к ресурсу делая много холостых оборотов занимая тем самым ядро "просто так", или лучше что бы он уступил дорогу другим потокам которые например могут вообще не ждать освобождения мьютекса и выполнять полезную работу? Даже если дорогу уступят потоку не из вашей программы то по идее не страшно. Возможно это приблизит следующую задачу из вашего приложения на шаг ближе к исполнению (тут уже надо смотреть конкретный планировщик задач)

Добавлено через 53 минуты
С другой стороны если критическая секция маленькая (например, просто взять задачу из очереди) тогда думаю уступать не выгодно т.к мьютекс вот-вот будет свободен и не надо переключать контекст. Короче говоря наверное надо действовать по ситуации не пытаясь использовать один и тот же мьютекс на все случаи жизни
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
02.01.2020, 03:40  [ТС]
Интересно, а как получить native_handle() для основного потока ?

Добавлено через 1 час 25 минут
С этим разобрался.

Добавлено через 7 минут
Но почему у меня timer_delete всё время возвращает код ошибки ? Как правильно пользоваться этой функцией, в случае когда надо остановить таймер ?

Добавлено через 7 минут
Извините, не в ту тему вопрос задал.
0
2735 / 890 / 331
Регистрация: 10.02.2018
Сообщений: 2,111
02.01.2020, 11:21
Цитата Сообщение от squareroot Посмотреть сообщение
Добрый день, не могу найти обоснование применения функции "уступить другим потокам" при реализации спинлока
Мне ваш вариант кажется ошибочным.
В моём понимании, спинлоком нужно блокировать очень короткие операции. Участки кода, которые выполняются долго должны блокироваться чем-то переключающим контекст и ждущим без загрузки ЦПУ, к примеру мьютексом. Если исходить из быстротечности кода внутри блокировок спинлока, то можно поступиться загрузкой ЦПУ на время ожидания блокировки, так как переключение контекста может занять времени больше чем ожидание освобождения спинлока. Вы вводите отдельный цикл с yield, который даёт искусственную задержку блокировки и при этом всё так же загружает ЦПУ.
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
02.01.2020, 12:22  [ТС]
Цитата Сообщение от Ygg Посмотреть сообщение
Мне ваш вариант кажется ошибочным.
В моём понимании, спинлоком нужно блокировать очень короткие операции. Участки кода, которые выполняются долго должны блокироваться чем-то переключающим контекст и ждущим без загрузки ЦПУ, к примеру мьютексом. Если исходить из быстротечности кода внутри блокировок спинлока, то можно поступиться загрузкой ЦПУ на время ожидания блокировки, так как переключение контекста может занять времени больше чем ожидание освобождения спинлока. Вы вводите отдельный цикл с yield, который даёт искусственную задержку блокировки и при этом всё так же загружает ЦПУ.
А спинлок в бусте тоже кажется ошибочным ?
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
02.01.2020, 15:39
Цитата Сообщение от squareroot Посмотреть сообщение
не стоит замарачиваться а взять boost::detail::spinlock, но он нормальный в плане производительности или это просто игрушка детская ?
это - очень правильный вопрос.

у меня был такой случай:
на мсдн есть страничка, где описывается как майкрософт рекомендует изготавливать спинлоки.
и вот я взял эту рекомендуемую готовую к употреблению версию спинлока.

а потом выполнил бенчмарки:
сравнительные тесты между spinlock, std::mutex и std::recursieve_mutex.
оказалось, что стандартные мутексы работают примерно с одинаковой скоростью.

с учетом статистических погрешностей можно считать,
что std::recursieve_mutex не уступает в скорости std::mutex
(а я почему то думал, что он будет самым тяжелым)

самым медленным же оказался spinlock.

замена стандартного мутекса на виндузятную критическую секцию так же не дала никакого перфоманса.

итого:
стандартные std::mutex и std::recursieve_mutex итак уже оптимизированны по самый ни балуй.
ну и нафига тогда нужны все эти велосипеды спинлоки?

Цитата Сообщение от squareroot Посмотреть сообщение
Я набрался наглости сделать свою реализацию, потомучто моя интуиция подсказывает что она лучше.
воот, моя интуиция тоже подсказывала,
что spinlock рекомендуемый майкрософт будет быстрее, чем std::mutex,
однако ж оказалось это не так.

Цитата Сообщение от squareroot Посмотреть сообщение
Но надо ещё всё это обосновать, а я даже не знаю откуда взять информацию.
ну так сделай бенчмарк: сравнительные тесты.
с кучей замеров, и красивыми табличками:
тесты дебаг версии,
тесты релиз версий,
тесты x86, тесты x64,
тесты на виндовс,
тесты на линукс,

по большому счету никого не волнует
Цитата Сообщение от squareroot Посмотреть сообщение
Полный треш, особенно yield()
если при этом ты смог наглядно проиллюстрировать профит:
решение со спинлоком работает эффективнее.
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
02.01.2020, 16:02  [ТС]
Цитата Сообщение от hoggy Посмотреть сообщение
если при этом ты смог наглядно проиллюстрировать профит:
решение со спинлоком работает эффективнее.
Он введён не для профита, а для безопасности, а безопасность штука субъективная, для многих. Мало кто имеет такой опыт чтобы обосновать, и даже если обоснуют, то те кто такой опыт не имеют сочтут это за домыслы.

Добавлено через 2 минуты
Цитата Сообщение от hoggy Посмотреть сообщение
это - очень правильный вопрос.

у меня был такой случай:
на мсдн есть страничка, где описывается как майкрософт рекомендует изготавливать спинлоки.
и вот я взял эту рекомендуемую готовую к употреблению версию спинлока.

а потом выполнил бенчмарки:
сравнительные тесты между spinlock, std::mutex и std::recursieve_mutex.
оказалось, что стандартные мутексы работают примерно с одинаковой скоростью.

с учетом статистических погрешностей можно считать,
что std::recursieve_mutex не уступает в скорости std::mutex
(а я почему то думал, что он будет самым тяжелым)

самым медленным же оказался spinlock.

замена стандартного мутекса на виндузятную критическую секцию так же не дала никакого перфоманса.

итого:
стандартные std::mutex и std::recursieve_mutex итак уже оптимизированны по самый ни балуй.
ну и нафига тогда нужны все эти велосипеды спинлоки?



воот, моя интуиция тоже подсказывала,
что spinlock рекомендуемый майкрософт будет быстрее, чем std::mutex,
однако ж оказалось это не так.

Какие конкретно времена у вас по мьютексу и на каком бенчмарке ?
И можно ссылку на мсдн, где рекомендация по изготовлению есть ?

Добавлено через 14 минут
Я не имею времени делать нормальный бенчмарк, могу скинуть номер своей карты. Если скинете денег, то сделаю бенчмарк(шутка)
0
2735 / 890 / 331
Регистрация: 10.02.2018
Сообщений: 2,111
02.01.2020, 16:41
Цитата Сообщение от squareroot Посмотреть сообщение
А спинлок в бусте тоже кажется ошибочным ?
Если под стандартным понимать цикл в котором exchange чередуется с yield, то не кажется. По-моему, именно такой вариант оптимален. Самый быстрый вариант, оставить в цикле только exchange, а yield убрать. Однако, в некоторых случаях это может оказаться плохим решением. Например, если у нас всего одно ядро и сейчас работает поток пытающийся получить блокировку, а уже получивший блокировку поток приостановлен, то получится бесполезно потраченный квант времени. Пока квант не закончится, первый поток будет повторять попытки блокировки, а второй поток спать. Что-то подобное возможно на множестве ядер, при условии полной загрузки всех ядер большим количеством потоков. Получивший блокировку поток может ждать своего кванта, а желающий получить блокировку будет занимать квант попытками exchange. В обоих случаях именно yield переключит контекст и тем самым оптимизирует работу компа. В большинстве же случаев (не 100% загрузка всех имеющихся ядер) yield будет практически бесполезен. Но это моё мнение, лично мне не приходилось активно пользоваться спинлоками.
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
02.01.2020, 17:20  [ТС]
Вообщем я понял что каждый считает свой спинлок единственно правильный, а если у когото по другому, то он должен иметь железные аргументы. Как в такой ситуации выполнять тестовые задания ума не приложу
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
02.01.2020, 18:09
Цитата Сообщение от squareroot Посмотреть сообщение
Вообщем я понял что каждый считает свой спинлок единственно правильный
Нет. Идея спинлока в том что в отличии от обычного мьютекса не нужно переключать контекст. Ожидание захвата происходит в user space, а не в кроватке для сна расположенной в kernel space.

По сути засыпающий спинлок это аналог обычного мьютекса +/- туда-сюда в зависимости от реализации.
Оба смотрят если доступа нет - идут спать.

Когда критическая секция мала то спинлок без засыпаний получается выгодным так как лучше покрутить "парочку" холостых итераций и захватить блокировку вместо того что бы идти спать переключая контекст в kernel space (переключение контекста дорогая операция).
Это будет быстрее.

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

Вот исходя из этих соображений и нужно принимать решение какую реализацию использовать.
Ну и конечно же будет круто делать бенчмарки и принимать взвешенное решение. Мало ли кто и где что-там наоптимизировал.
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
02.01.2020, 18:16  [ТС]
Цитата Сообщение от Undisputed Посмотреть сообщение

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

Вот исходя из этих соображений и нужно принимать решение какую реализацию использовать.
Ну и конечно же будет круто делать бенчмарки и принимать взвешенное решение. Мало ли кто и где что-там наоптимизировал.
Я просто не хочу спорить, потомучто у меня пока нет своего мнения и моя цель в данной теме другая, но поверьте, Вам смогут очень хоршо возразить.
Я всётаки жду что мне hoggy скинет ссылку на рекомендацию по спинлокам от msdn.
В данной ситуации наверно остаётся только аппелировать к чемуто авторитетному.
Но если кто поделиться своим бенчмарком, то я буду рад. Я не имею возможности слишкои сильно увлекаться одним спинлоком.
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
03.01.2020, 00:14
Я чет не понимаю? А где тут спинлок?
Мютекс реализуется "на спинлоке" а не наоборот.

В реальности как я помню мютексы используют комбинированный подход.
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
04.01.2020, 12:50
Цитата Сообщение от squareroot Посмотреть сообщение
Я не имею возможности слишкои сильно увлекаться одним спинлоком.
А ты и не увлекайся. Тебе же выше вроде написали, что там проблема не в спинлоке, а в том, где ты такие мьютексы будешь использовать. Т.е. спинлок-мьютексы эффективны только для очень коротких блокировок, типа добавления/удаления из списка и т.д..
Сам спинлок реализуется ровно в три строчки, при помощи std::atomic_flag. Можно с yield, можно и без него. Лично я делаю с yield, т.к. он относительно недорогой, не усыпляет поток, и не факт, что потоки выполняются на разных процессорах.

Добавлено через 26 минут
Про "он относительно недорогой, не усыпляет поток" я, конечно, загнал
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
05.01.2020, 00:05  [ТС]
А как называется примитив синхронизациии где доступ к ресурсу не ведётся, а используется try_lock ?

Добавлено через 17 минут
А как называется примитив синхронизациии где борьба за доступ к ресурсу не ведётся, а используется try_lock ?
0
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
07.01.2020, 18:16
Цитата Сообщение от hoggy Посмотреть сообщение
а потом выполнил бенчмарки:
сравнительные тесты между spinlock, std::mutex и std::recursieve_mutex.
оказалось, что стандартные мутексы работают примерно с одинаковой скоростью.
с учетом статистических погрешностей можно считать,
что std::recursieve_mutex не уступает в скорости std::mutex
(а я почему то думал, что он будет самым тяжелым)
самым медленным же оказался spinlock.
на самом деле это не удивительно. потому что спинлоки надо использовать только в очень специфических ситуациях. и надо в каждой конкретной задаче замерять, имеет ли это профит. в вашем бенчмарке, видимо, не имело.

Цитата Сообщение от squareroot Посмотреть сообщение
А спинлок в бусте тоже кажется ошибочным ?
я думаю, что спинлок в бусте(да и mutex в std, я думаю) просто является адаптивным. он пытается захватить лок в цикле несколько раз, а потом сдаётся и усыпляет поток.
https://lwn.net/Articles/704843/
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
08.01.2020, 01:28
Цитата Сообщение от GbaLog- Посмотреть сообщение
потому что спинлоки надо использовать только в очень специфических ситуациях.
расскажи, что за ситуации такие.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
08.01.2020, 01:28
Помогаю со студенческими работами здесь

Как проинициализировать std::stack<const int> obj ( std::stack<int>{} );
добрый день. вопрос в коде: http://rextester.com/VCVVML6656 #include &lt;iostream&gt; #include &lt;stack&gt; //-std=c++14...

std::filesystem && std::asio и пр
Пытался найти хоть какие-то сроки включения всего этого в стандарт (так же ожидается lexical_cast, any, string_algo и т.д.) и вообщем везде...

Ошибка: E2034 Cannot convert 'int' to 'std::vector<std::vector<TRabbitCell,std::allocator<TRabbitCell>>...
Есть двухмерный вектор: std::vector&lt;std::vector&lt;TRabbitCell&gt; &gt; *cells(5, 10); Пытаюсь заполнить его объектами класса...

Перевод строк std::string, std::wstring в Unicode (String)
Собственно столкнулся с проблемой, как корректно перевести к примеру текст из Edit1-&gt;Text в std::string или std::wstring и...

This_thread::yield что делает?
Добрый день! Что делает функция yield(), можете привести небольшой пример, если не сложно?


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
Реалии
Hrethgir 01.03.2026
Нет, я не закончил до сих пор симулятор. Эта задача сложнее. Не получилось уйти в плавсостав, но оно и к лучшему, возможно. Точнее получалось - но сварщиком в палубную команду, а это значит, в моём. . .
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
SDL3 для Web (WebAssembly): Сборка библиотек: SDL3, Box2D, FreeType, SDL3_ttf, SDL3_mixer и SDL3_image из исходников с помощью CMake и Emscripten
8Observer8 27.02.2026
Недавно вышла версия 3. 4. 2 библиотеки SDL3. На странице официальной релиза доступны исходники, готовые DLL (для x86, x64, arm64), а также библиотеки для разработки под Android, MinGW и Visual Studio. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru