Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Bushmeister
22 / 22 / 6
Регистрация: 19.03.2015
Сообщений: 137
#1

Один mutex на несколько функций - C++

19.04.2016, 13:56. Просмотров 902. Ответов 50
Метки нет (Все метки)

Есть три функции, которые могут работать с одним вектором в одно и то же время из разных потоков. Можно ли использовать один мьютекс на эти несколько функций, чтобы не синхронизировать работу 3-х мьютексов?
Код чисто для примера, чтобы было понятно, чего я хочу
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
mutex m;
vector<int> vec;
 
void Add(int i)
{
    m.lock();
        try
        {
            vec.push_back(i);
        }
        catch(exception ex)
        {
            m.unlock();
            throw ex;
        }
    m.unlock(); //все ок.
}
 
void Remove(int i)
{
    m.lock()
        try
        {
            //находим с помощью итераторов индекс с значением i и erasим его
            ...
        }
        catch(exception ex)
        {
            //если произойдет ошибка, анлокним мьютекс, чтобы другие функции могли
            //продолжить работу, а ошибку пробросим выше.
            m.unlock();
            throw ex;
        }
    m.unlock(); //все ок.
}
 
void Read(int index)
{
    m.lock()
        try
        {
            for (int i=0; i<vec.size(); i++)
            {
                if (i==index)
                {
                    vec[i].....
                    //шаманим со значением по индексу...
                }
            }
        }
        catch(exception ex)
        {
            m.unlock();
            throw ex;
        }
    m.unlock(); //все ок.
}
Лучшие ответы (1)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
nmcf
5274 / 4594 / 1539
Регистрация: 14.04.2014
Сообщений: 18,249
19.04.2016, 22:56     Один mutex на несколько функций #16
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Такая очередь просто никому не нужна.
Я не понял, при чём тут race condition. Нужно просто, чтобы потоки, получали управление в том порядке в каком они повисли на мьютексе - FIFO.
По поводу нужности или ненужности - бывали тут темы, в которых просили реализовать именно такое поведение, например, чтобы потоки выполняли обработку строго друг за другом.
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
3697 / 1972 / 515
Регистрация: 18.10.2014
Сообщений: 3,559
19.04.2016, 23:40     Один mutex на несколько функций #17
Цитата Сообщение от nmcf Посмотреть сообщение
Я не понял, при чём тут race condition. Нужно просто, чтобы потоки, получали управление в том порядке в каком они повисли на мьютексе - FIFO.
Если несколько потоков конкурируют за один mutex, то порядок их прихода на этот mutex - это просто ярчайший, хрестоматийнейший пример "гонки".

Цитата Сообщение от nmcf Посмотреть сообщение
в которых просили реализовать именно такое поведение, например, чтобы потоки выполняли обработку строго друг за другом.
Потоки, ждущие одного и тот же mutex, и так будут выполнять обработку "строго друг за другом". А вот требовать того, чтобы это "строго друг за другом" делалось в том же порядке, к котором потоки прибыли на ожидание - это уже к mutex никакого отношения не имеет. Сама фундаментальная идея mutex в самой своей основе предполагает, что порядок входа никакого значения не имеет. Ибо порядок прихода на ожидание - это "гонка".

Если кто-то такого просил - флаг им в руки, но в общем случае это бессмысленная просьба - попытка душить симптомы проблемы, вместо того, чтобы решать саму проблему. Поведение программы не должно зависеть от результатов "гонки". Кто-то "просил" этого? Ну так скажите им, чтобы перестали "просить".
warhast
11 / 11 / 3
Регистрация: 02.02.2014
Сообщений: 55
20.04.2016, 09:27     Один mutex на несколько функций #18
Гонки тут ни при чем, речь о свойстве инструментов синхронизации. И стандарт в этом отношении ничего не требует, так что если в некоторой системе родной mutex окажется fair - то и std::mutex в ней будет fair.

По реализации - см. TBB от Intel, queuing_mutex, например.
Bushmeister
22 / 22 / 6
Регистрация: 19.03.2015
Сообщений: 137
20.04.2016, 10:21  [ТС]     Один mutex на несколько функций #19
Ой, вот только не надо тут пальцы гнуть, если ещё кто-то не вникал в тему с мьютексами и знает их поверхностно, без практики. Похоже, придется напомнить, что это раздел для начинающих в C++. Для вас "странные вопросы" - абсолютно нормальные, логичные для тех, кто ещё не работал с этим серьезно и желает получить правильное решение, чтобы потом не наступать на грабли.
Цитата Сообщение от Nosey Посмотреть сообщение
Bushmeister,
Мне просто больно смотреть и не написать следующее:
Ну что поделать. В различных статьях, в которых я смотрел применение и работу мьютекса, во многих случаях использовали lock/unlock, а не lock_guard. Теперь-то жить стало проще)
Цитата Сообщение от Nosey Посмотреть сообщение
for (auto& i : vec)
Руки никак не доходили для изучения таких циклов. Видимо настало время)
Nosey
1346 / 397 / 107
Регистрация: 22.10.2014
Сообщений: 861
Завершенные тесты: 2
20.04.2016, 10:37     Один mutex на несколько функций #20
Цитата Сообщение от Bushmeister Посмотреть сообщение
Ой, вот только не надо тут пальцы гнуть
Я ни коем образом не гнул, извиняюсь если так вышло ) Я лишь хотел подсказать куда копать дальше.
Цитата Сообщение от Bushmeister Посмотреть сообщение
Ну что поделать. В различных статьях, в которых я смотрел применение и работу мьютекса, во многих случаях использовали lock/unlock, а не lock_guard.
И это в общем отлично.
Так что как дочитаете, милости прошу:
http://en.cppreference.com/w/cpp/thread
и следом:
http://www.boost.org/doc/libs/1_60_0/doc/html/thread/
rikimaru2013
C++ Game Dev
2419 / 1113 / 240
Регистрация: 30.11.2013
Сообщений: 3,661
20.04.2016, 11:41     Один mutex на несколько функций #21
Цитата Сообщение от Nosey Посмотреть сообщение
std::begin(vec), std::end(vec)
Моя школа А то все пишут vec.begin()
nmcf
5274 / 4594 / 1539
Регистрация: 14.04.2014
Сообщений: 18,249
20.04.2016, 13:07     Один mutex на несколько функций #22
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Если несколько потоков конкурируют за один mutex, то порядок их прихода на этот mutex - это просто ярчайший, хрестоматийнейший пример "гонки".
Гонка - это когда мьютекса нет вообще и потоки мешают друг другу.

Если несколько потоков используют мьютекс для доступа к ресурсу, при этом порядок обращения к мьютексу и время удержания произвольные, то где гарантия, что один и тот же поток не будет неограниченно долго удерживать мьютекс просто освобождая и тут же захватывая его повторно, ведь очереди нет, и не гарантируется, что освобождение мьютекса одним поток обязательно активирует ожидающих?
Bushmeister
22 / 22 / 6
Регистрация: 19.03.2015
Сообщений: 137
20.04.2016, 13:38  [ТС]     Один mutex на несколько функций #23
Цитата Сообщение от Nosey Посмотреть сообщение
Я ни коем образом не гнул, извиняюсь если так вышло ) Я лишь хотел подсказать куда копать дальше.
Ох, забыл процитировать сообщение. Да не, не Вам это, а TheCalligrapher'у. Ваше сообщение очень кстати.
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
3697 / 1972 / 515
Регистрация: 18.10.2014
Сообщений: 3,559
20.04.2016, 20:32     Один mutex на несколько функций #24
Цитата Сообщение от nmcf Посмотреть сообщение
Гонка - это когда мьютекса нет вообще и потоки мешают друг другу.
Ни в коем случае.

Race condition ("гонка") - это огромный класс семантических проблем, суть которых сводится к тому, что программа пытается завязываться на такие предположения о многопоточном поведении, которые на самом деле является неопределенными (unspecified или undefined). А именно, когда программа пытается делать предположения о существовании некоего детерминированного "порядка" или "скорости" выполнения потоков.

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

Вот вам искусственный пример гонки, причем буквальной: пусть у меня есть глобальная переменная int i = 0 и несколько одинаковых потоков, которые, кроме прочего, делают ++i и запоминают результат. Пусть я запускаю эти потоки поочередно с задержкой Dt по времени между потоками. И я предполагаю, что те потоки, которые стартовали раньше, "доберутся" до ++i тоже раньше. Соответственно, я предполагаю, что первый запущенный поток получит из i значение - 1, второй - 2 и т.д. Пусть я в дальнейшем коде сильно завишу от выполнения этого предположения.

Вот это - яркий пример гонки. Мое предположение - грубейшим образом некорректно. То, что некий поток стартовал позже, никак не мешает ему обогнать более ранний поток в процессе выполнения. При этом заоболачивание доступа к ++i в mutex никак делу не поможет - выполнение моего предположения все равно не гарантируется и оно не будет выполняться. Вот это - классический race condition. Заоболочив доступ к ++i в mutex я лишь перенес точку финиша в этой гонке, но саму гонку и ее негативные последствия никак не устранил.

Нерадивый программист в такой ситуации может начать увеличивать величину задержки Dt, в надежде на то, что для какого-то значения Dt порядок прихода потоков на ++i, наконец, станет совпадать с порядком их запуска. Понятно, что это не более чем профанация.

В такой ситуации, если я действительно хочу, чтобы потоки выполняли ++i в некотором четко определенном мною порядке, я должен буду самостоятельно насильно ловить и задерживать "выбившиеся вперед" потоки. И делать это придется вручную.

Цитата Сообщение от nmcf Посмотреть сообщение
Если несколько потоков используют мьютекс для доступа к ресурсу, при этом порядок обращения к мьютексу и время удержания произвольные, то где гарантия, что один и тот же поток не будет неограниченно долго удерживать мьютекс просто освобождая и тут же захватывая его повторно, ведь очереди нет, и не гарантируется, что освобождение мьютекса одним поток обязательно активирует ожидающих?
Такая гарантия и есть, и нет.

Такая гарантия есть, потому что освобождение и последующий захват одного mutex потоком A - операция неатомарная. В традиционной реализации, если в этот момент какой-то другой поток B ожидал этого же mutex и был в этот момент готов к выполнению, этот поток B тут же захватит этот mutex еще в момент освобождения его потоком A. Как бы быстро A не попытался снова захватить mutex, он все равно "не успеет".

Такой гарантии нет например потому, что ожидающий поток B в момент освобождения mutex может оказаться не готов к выполнению. Например, ОС могла "на секундочку" захватить ресурсы потока B и переиспользовать их для решения каких-то своих внутренних задач (типа обслуживания прерывания неким внутренним системным потоком C). Поток B на это время будет "заморожен". Т.е. может получится так, что поток B "прохлопает" свою возможность захватить mutex, и поток A сможет успеть снова захватить его прямо под носом у потока B.

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

Но опять же, в недискриминирующем отношении ОС к потокам не содержится никаких гарантий порядка выполнения потоков. Если вам нужен порядок - огранизуйте его сами. И многопоточное программирование предполагает дизайн программы по принципу: если что-то очень маловероятно, но теоретически возможно, то оно рано или поздно произойдет.

Добавлено через 10 минут
Цитата Сообщение от Bushmeister Посмотреть сообщение
Ой, вот только не надо тут пальцы гнуть, если ещё кто-то не вникал в тему с мьютексами и знает их поверхностно, без практики. Похоже, придется напомнить, что это раздел для начинающих в C++. Для вас "странные вопросы" - абсолютно нормальные, логичные для тех, кто ещё не работал с этим серьезно и желает получить правильное решение, чтобы потом не наступать на грабли.
Перед вами никто не "гнет пальцы".

Когда некто в форуме "для начинающих математиков" задает вопрос типа "Решал уравнение x + 2 = 4. Получил ответ x=3, но что-то не сходится. Где ошибка?", то на такой вопрос можно дать два принципиально разных ответа. Первый ответ: "Правильное решение x=2. Свободен.". Второй ответ: "Покажи, как ты получил такой странный результат (а мы покажем тебе, где именно ты ошибся в процессе решения)". Я лично считаю, что в такой "странной" ситуации, как "решал x + 2 = 4, получил x=3" первый вариант ответа на самом деле бесполезен, а осмысленен именно и только второй вариант ответа.

Вот так же и здесь, когда я у вас спрашиваю, "откуда возник такой вопрос", цель этого - именно понять, какая цепочка умозаключений привела вас к "странному" выводу, что для трех функций необходимо три мьютекса, и затем уже искать ошибку в этой цепочке. Ни больше, ни меньше.
nmcf
5274 / 4594 / 1539
Регистрация: 14.04.2014
Сообщений: 18,249
20.04.2016, 23:14     Один mutex на несколько функций #25
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Такая гарантия и есть, и нет.
Ну вот и я о том же.
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
не будут как-то выражено дискриминироваться планировщиком потоков.
Это если они просто выполняются независимо. А если задействован мьютекс, то они сами начинают мешать планировщику.
avgoor
884 / 519 / 112
Регистрация: 05.12.2015
Сообщений: 1,464
20.04.2016, 23:32     Один mutex на несколько функций #26
Цитата Сообщение от nmcf Посмотреть сообщение
А если задействован мьютекс, то они сами начинают мешать планировщику.
С чего бы вдруг?
nmcf
5274 / 4594 / 1539
Регистрация: 14.04.2014
Сообщений: 18,249
21.04.2016, 10:38     Один mutex на несколько функций #27
Цитата Сообщение от avgoor Посмотреть сообщение
С чего бы вдруг?
Потому что обращение к мьютексу будет останавливать потоки, и тем самым будет перераспределяться время.
avgoor
884 / 519 / 112
Регистрация: 05.12.2015
Сообщений: 1,464
21.04.2016, 11:48     Один mutex на несколько функций #28
Цитата Сообщение от nmcf Посмотреть сообщение
Потому что обращение к мьютексу будет останавливать потоки,
А кто будет останавливать потоки при обращении к мьютексу, если не планировщик? А если это не системный мьютекс, а простой спинлок?
nmcf
5274 / 4594 / 1539
Регистрация: 14.04.2014
Сообщений: 18,249
21.04.2016, 11:55     Один mutex на несколько функций #29
avgoor, дело не в том, что останавливает планировщик, а в том по чьей команде.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
21.04.2016, 12:01     Один mutex на несколько функций
Еще ссылки по теме:
Заменить один символ на несколько C++
Создание матрицы и сортировка, используя несколько функций C++
Массивы Функций. DirectX 11. Отобразить несколько моделей C++
C++ Насколько целесообразно разбивать программу на несколько функций?
Слить несколько txt-файлов в один C++

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

Или воспользуйтесь поиском по форуму:
avgoor
884 / 519 / 112
Регистрация: 05.12.2015
Сообщений: 1,464
21.04.2016, 12:01     Один mutex на несколько функций #30
Цитата Сообщение от nmcf Посмотреть сообщение
а в том по чьей команде
Какая разница? Например в винде, если вы в цикле обработки событий вызываете Sleep(0) - вы помогаете планировщику, а не наоборот.
А вообще, планировщик делают с оглядкой на такие вещи.
Yandex
Объявления
21.04.2016, 12:01     Один mutex на несколько функций
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru