Форум программистов, компьютерный форум, киберфорум
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. Показов 4720. Ответов 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
2734 / 888 / 331
Регистрация: 10.02.2018
Сообщений: 2,097
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
2734 / 888 / 331
Регистрация: 10.02.2018
Сообщений: 2,097
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
8484 / 6151 / 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
Ответ Создать тему
Новые блоги и статьи
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru