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

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

Восстановить пароль Регистрация
 
 
Bushmeister
22 / 22 / 6
Регистрация: 19.03.2015
Сообщений: 137
19.04.2016, 13:56     Один mutex на несколько функций #1
Есть три функции, которые могут работать с одним вектором в одно и то же время из разных потоков. Можно ли использовать один мьютекс на эти несколько функций, чтобы не синхронизировать работу 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)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
rikimaru2013
C++ Game Dev
 Аватар для rikimaru2013
2274 / 990 / 226
Регистрация: 30.11.2013
Сообщений: 3,297
20.04.2016, 11:41     Один mutex на несколько функций #21
Цитата Сообщение от Nosey Посмотреть сообщение
std::begin(vec), std::end(vec)
Моя школа А то все пишут vec.begin()
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
nmcf
4441 / 3779 / 1278
Регистрация: 14.04.2014
Сообщений: 14,872
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
С чаем беда...
Эксперт С++
 Аватар для TheCalligrapher
3130 / 1570 / 424
Регистрация: 18.10.2014
Сообщений: 2,907
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
4441 / 3779 / 1278
Регистрация: 14.04.2014
Сообщений: 14,872
20.04.2016, 23:14     Один mutex на несколько функций #25
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Такая гарантия и есть, и нет.
Ну вот и я о том же.
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
не будут как-то выражено дискриминироваться планировщиком потоков.
Это если они просто выполняются независимо. А если задействован мьютекс, то они сами начинают мешать планировщику.
avgoor
562 / 352 / 83
Регистрация: 05.12.2015
Сообщений: 1,137
20.04.2016, 23:32     Один mutex на несколько функций #26
Цитата Сообщение от nmcf Посмотреть сообщение
А если задействован мьютекс, то они сами начинают мешать планировщику.
С чего бы вдруг?
nmcf
4441 / 3779 / 1278
Регистрация: 14.04.2014
Сообщений: 14,872
21.04.2016, 10:38     Один mutex на несколько функций #27
Цитата Сообщение от avgoor Посмотреть сообщение
С чего бы вдруг?
Потому что обращение к мьютексу будет останавливать потоки, и тем самым будет перераспределяться время.
avgoor
562 / 352 / 83
Регистрация: 05.12.2015
Сообщений: 1,137
21.04.2016, 11:48     Один mutex на несколько функций #28
Цитата Сообщение от nmcf Посмотреть сообщение
Потому что обращение к мьютексу будет останавливать потоки,
А кто будет останавливать потоки при обращении к мьютексу, если не планировщик? А если это не системный мьютекс, а простой спинлок?
nmcf
4441 / 3779 / 1278
Регистрация: 14.04.2014
Сообщений: 14,872
21.04.2016, 11:55     Один mutex на несколько функций #29
avgoor, дело не в том, что останавливает планировщик, а в том по чьей команде.
avgoor
562 / 352 / 83
Регистрация: 05.12.2015
Сообщений: 1,137
21.04.2016, 12:01     Один mutex на несколько функций #30
Цитата Сообщение от nmcf Посмотреть сообщение
а в том по чьей команде
Какая разница? Например в винде, если вы в цикле обработки событий вызываете Sleep(0) - вы помогаете планировщику, а не наоборот.
А вообще, планировщик делают с оглядкой на такие вещи.
nmcf
4441 / 3779 / 1278
Регистрация: 14.04.2014
Сообщений: 14,872
21.04.2016, 14:31     Один mutex на несколько функций #31
Цитата Сообщение от avgoor Посмотреть сообщение
А вообще, планировщик делают с оглядкой на такие вещи.
Ну и почему нет очереди тогда? Логично же передавать управление тому, кто дольше ждёт.
warhast
7 / 7 / 3
Регистрация: 02.02.2014
Сообщений: 51
21.04.2016, 15:06     Один mutex на несколько функций #32
Логично потратить как можно меньше времени и разбудить первый попавшийся ждущий поток. Fair синхронизация нужна слишком редко, чтобы ради нее в ядро вкорячивать лишний код, тем более в таком месте.
nmcf
4441 / 3779 / 1278
Регистрация: 14.04.2014
Сообщений: 14,872
21.04.2016, 15:14     Один mutex на несколько функций #33
Цитата Сообщение от warhast Посмотреть сообщение
потратить как можно меньше времени и разбудить первый попавшийся ждущий поток
Попавшийся где? Они же хранятся в каком-то контейнере, значит очерёдность там - не проблема.
avgoor
562 / 352 / 83
Регистрация: 05.12.2015
Сообщений: 1,137
21.04.2016, 17:06     Один mutex на несколько функций #34
Цитата Сообщение от nmcf Посмотреть сообщение
Ну и почему нет очереди тогда? Логично же передавать управление тому, кто дольше ждёт.
Цитата Сообщение от nmcf Посмотреть сообщение
Попавшийся где? Они же хранятся в каком-то контейнере, значит очерёдность там - не проблема.
Там есть какая-то очередность, но она, в общем случае, не совпадает с FIFO, потому, что это никому не надо, TheCalligrapher уже объяснил почему. Если вам так нужна эта очередь, организуйте ее самостоятельно. Но учитывайте, что никак невозможно заранее определить порядок в котором потоки в эту очередь попадут.
warhast
7 / 7 / 3
Регистрация: 02.02.2014
Сообщений: 51
21.04.2016, 17:17     Один mutex на несколько функций #35
Пример: поток освобождает мьютекс (лежащий за ним футекс) и будит ожидающего. Но в этот момент набегает новый поток и хватает освободившийся футекс. Проснувшийся ожидавший видит, что прощелкал свой шанс и засыпает обратно, причем уже в конце очереди. И вот такое проверять никто не будет без нужды.
avgoor
562 / 352 / 83
Регистрация: 05.12.2015
Сообщений: 1,137
21.04.2016, 17:17     Один mutex на несколько функций #36
Поясню подробнее. Один поток может 10 раз успеть захватить и освободить мьютекс, пока второй доберется до захвата этого мьютекса, т.е. постановки в очередь.
nmcf
4441 / 3779 / 1278
Регистрация: 14.04.2014
Сообщений: 14,872
21.04.2016, 18:04     Один mutex на несколько функций #37
Цитата Сообщение от warhast Посмотреть сообщение
поток освобождает мьютекс (лежащий за ним футекс) и будит ожидающего. Но в этот момент набегает новый поток и хватает освободившийся футекс.
Не понял я твой пример. Потоки активируются не сами собой, а извне. Если всё, как ты описал, то как вообще гарантировать хоть какую-то равномерность выполнения?
Цитата Сообщение от avgoor Посмотреть сообщение
Один поток может 10 раз успеть захватить и освободить мьютекс, пока второй доберется до захвата этого мьютекса
Я об этом и говорю. Без очереди будет бардак - одни оттеснят других.
avgoor
562 / 352 / 83
Регистрация: 05.12.2015
Сообщений: 1,137
21.04.2016, 18:23     Один mutex на несколько функций #38
Цитата Сообщение от nmcf Посмотреть сообщение
Я об этом и говорю. Без очереди будет бардак - одни оттеснят других
1) Мьютекс почти всегда свободен. Потому, что если он почти всегда занят - практически вы имеете однопоточный алгоритм с оверхедом в виде потоков.
2) Если потоки равнозначны (читай делают одно и то же) - какая вам разница, какой поток захватит мьютекс?
3) Если потоки не равнозначны - какая разница, какой из них первым попытался захатить мьютекс, если все равно нужен приоритет?
Исходя из вышесказанного зачем нужна строгая очередность в захвате мьютексов?

Добавлено через 8 минут
Цитата Сообщение от nmcf Посмотреть сообщение
Без очереди будет бардак - одни оттеснят других
Но мьютексы к этому не имеют никакого отношения.
warhast
7 / 7 / 3
Регистрация: 02.02.2014
Сообщений: 51
21.04.2016, 18:27     Один mutex на несколько функций #39
О какой именно "равномерности" речь?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
21.04.2016, 18:50     Один mutex на несколько функций
Еще ссылки по теме:

Слить несколько txt-файлов в один C++
C++ Насколько целесообразно разбивать программу на несколько функций?
Несколько new на один и тот же указатель C++
Реализовать несколько функций C++
Создание матрицы и сортировка, используя несколько функций C++

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

Или воспользуйтесь поиском по форуму:
nmcf
4441 / 3779 / 1278
Регистрация: 14.04.2014
Сообщений: 14,872
21.04.2016, 18:50     Один mutex на несколько функций #40
Цитата Сообщение от avgoor Посмотреть сообщение
Мьютекс почти всегда свободен
Откуда это следует? И на сколько он должен быть свободен, чтобы гарантировать захват всеми желающими, на секунду, на минуту?
Цитата Сообщение от avgoor Посмотреть сообщение
Исходя из вышесказанного зачем нужна строгая очередность в захвате мьютексов?
Я уже сказал - в первую очередь, чтобы потоки выполнялись равноправно.

Добавлено через 2 минуты
Цитата Сообщение от warhast Посмотреть сообщение
О какой именно "равномерности" речь?
О равномерном выполнении всех потоков. Чтобы все получали шанс и время, а не находились в состоянии ожидания, пока кто-то вне очереди перехватывает мьютекс.
Yandex
Объявления
21.04.2016, 18:50     Один mutex на несколько функций
Ответ Создать тему
Опции темы

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