Форум программистов, компьютерный форум, киберфорум
Наши страницы

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

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

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

19.04.2016, 13:56. Просмотров 1001. Ответов 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(); //все ок.
}
2
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
19.04.2016, 13:56
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Один mutex на несколько функций (C++):

Реализовать несколько функций - C++
Реализовать несколько функций с различным числом аргументов и типами значений,что возвращаются, можно выбрать предложенные или произвольные...

Добавить несколько функций - C++
привет всем) вот есть код на С++ в консольном приложении VS 2008 - калькулятор с функциями сложения, вычитания, умножения и деления....

Разбить на несколько функций - C++
Доброго времени суток, подскажите пожалуйста, нужно разбить одну большую функцию, на несколько. Вот исходные код с одной...

Нужно реализовать несколько функций - C++
// копирует source в destination и возвращает указатель на destination char* strcpy(char* destination, const char* source); //...

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

Несколько функций - активна только одна - C++
Вообщем есть несколько функций? int Fun1,Fun2,Fun3,Fun4; if(Fun1){Действие} if(Fun2){Действие} if(Fun3){Действие} ...

50
nmcf
5756 / 5067 / 1734
Регистрация: 14.04.2014
Сообщений: 20,749
19.04.2016, 22:56 #16
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Такая очередь просто никому не нужна.
Я не понял, при чём тут race condition. Нужно просто, чтобы потоки, получали управление в том порядке в каком они повисли на мьютексе - FIFO.
По поводу нужности или ненужности - бывали тут темы, в которых просили реализовать именно такое поведение, например, чтобы потоки выполняли обработку строго друг за другом.
0
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
4009 / 2232 / 557
Регистрация: 18.10.2014
Сообщений: 3,853
19.04.2016, 23:40 #17
Цитата Сообщение от nmcf Посмотреть сообщение
Я не понял, при чём тут race condition. Нужно просто, чтобы потоки, получали управление в том порядке в каком они повисли на мьютексе - FIFO.
Если несколько потоков конкурируют за один mutex, то порядок их прихода на этот mutex - это просто ярчайший, хрестоматийнейший пример "гонки".

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

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

По реализации - см. TBB от Intel, queuing_mutex, например.
0
Bushmeister
22 / 22 / 6
Регистрация: 19.03.2015
Сообщений: 137
20.04.2016, 10:21  [ТС] #19
Ой, вот только не надо тут пальцы гнуть, если ещё кто-то не вникал в тему с мьютексами и знает их поверхностно, без практики. Похоже, придется напомнить, что это раздел для начинающих в C++. Для вас "странные вопросы" - абсолютно нормальные, логичные для тех, кто ещё не работал с этим серьезно и желает получить правильное решение, чтобы потом не наступать на грабли.
Цитата Сообщение от Nosey Посмотреть сообщение
Bushmeister,
Мне просто больно смотреть и не написать следующее:
Ну что поделать. В различных статьях, в которых я смотрел применение и работу мьютекса, во многих случаях использовали lock/unlock, а не lock_guard. Теперь-то жить стало проще)
Цитата Сообщение от Nosey Посмотреть сообщение
for (auto& i : vec)
Руки никак не доходили для изучения таких циклов. Видимо настало время)
0
Nosey
1349 / 400 / 107
Регистрация: 22.10.2014
Сообщений: 863
Завершенные тесты: 2
20.04.2016, 10:37 #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/
1
rikimaru2013
C++ Game Dev
2468 / 1137 / 240
Регистрация: 30.11.2013
Сообщений: 3,700
20.04.2016, 11:41 #21
Цитата Сообщение от Nosey Посмотреть сообщение
std::begin(vec), std::end(vec)
Моя школа А то все пишут vec.begin()
0
nmcf
5756 / 5067 / 1734
Регистрация: 14.04.2014
Сообщений: 20,749
20.04.2016, 13:07 #22
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Если несколько потоков конкурируют за один mutex, то порядок их прихода на этот mutex - это просто ярчайший, хрестоматийнейший пример "гонки".
Гонка - это когда мьютекса нет вообще и потоки мешают друг другу.

Если несколько потоков используют мьютекс для доступа к ресурсу, при этом порядок обращения к мьютексу и время удержания произвольные, то где гарантия, что один и тот же поток не будет неограниченно долго удерживать мьютекс просто освобождая и тут же захватывая его повторно, ведь очереди нет, и не гарантируется, что освобождение мьютекса одним поток обязательно активирует ожидающих?
0
Bushmeister
22 / 22 / 6
Регистрация: 19.03.2015
Сообщений: 137
20.04.2016, 13:38  [ТС] #23
Цитата Сообщение от Nosey Посмотреть сообщение
Я ни коем образом не гнул, извиняюсь если так вышло ) Я лишь хотел подсказать куда копать дальше.
Ох, забыл процитировать сообщение. Да не, не Вам это, а TheCalligrapher'у. Ваше сообщение очень кстати.
0
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
4009 / 2232 / 557
Регистрация: 18.10.2014
Сообщений: 3,853
20.04.2016, 20:32 #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" первый вариант ответа на самом деле бесполезен, а осмысленен именно и только второй вариант ответа.

Вот так же и здесь, когда я у вас спрашиваю, "откуда возник такой вопрос", цель этого - именно понять, какая цепочка умозаключений привела вас к "странному" выводу, что для трех функций необходимо три мьютекса, и затем уже искать ошибку в этой цепочке. Ни больше, ни меньше.
4
nmcf
5756 / 5067 / 1734
Регистрация: 14.04.2014
Сообщений: 20,749
20.04.2016, 23:14 #25
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Такая гарантия и есть, и нет.
Ну вот и я о том же.
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
не будут как-то выражено дискриминироваться планировщиком потоков.
Это если они просто выполняются независимо. А если задействован мьютекс, то они сами начинают мешать планировщику.
0
avgoor
962 / 596 / 130
Регистрация: 05.12.2015
Сообщений: 1,681
20.04.2016, 23:32 #26
Цитата Сообщение от nmcf Посмотреть сообщение
А если задействован мьютекс, то они сами начинают мешать планировщику.
С чего бы вдруг?
0
nmcf
5756 / 5067 / 1734
Регистрация: 14.04.2014
Сообщений: 20,749
21.04.2016, 10:38 #27
Цитата Сообщение от avgoor Посмотреть сообщение
С чего бы вдруг?
Потому что обращение к мьютексу будет останавливать потоки, и тем самым будет перераспределяться время.
0
avgoor
962 / 596 / 130
Регистрация: 05.12.2015
Сообщений: 1,681
21.04.2016, 11:48 #28
Цитата Сообщение от nmcf Посмотреть сообщение
Потому что обращение к мьютексу будет останавливать потоки,
А кто будет останавливать потоки при обращении к мьютексу, если не планировщик? А если это не системный мьютекс, а простой спинлок?
0
nmcf
5756 / 5067 / 1734
Регистрация: 14.04.2014
Сообщений: 20,749
21.04.2016, 11:55 #29
avgoor, дело не в том, что останавливает планировщик, а в том по чьей команде.
0
avgoor
962 / 596 / 130
Регистрация: 05.12.2015
Сообщений: 1,681
21.04.2016, 12:01 #30
Цитата Сообщение от nmcf Посмотреть сообщение
а в том по чьей команде
Какая разница? Например в винде, если вы в цикле обработки событий вызываете Sleep(0) - вы помогаете планировщику, а не наоборот.
А вообще, планировщик делают с оглядкой на такие вещи.
0
21.04.2016, 12:01
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
21.04.2016, 12:01
Привет! Вот еще темы с ответами:

Объединить несколько циклов в один - C++
Здравствуйте! Соорудил небольшую систему для прохода по одномерному массиву с целью выдергивания последнего члена в цепочке...

Заменить один символ на несколько - C++
Добрый день, у меня вопрос по С++. Как сделать что бы в чаре менял 1 символ на несколько? Не могу постичь этого. И ещё как мне заменять...

Несколько new на один и тот же указатель - C++
char* p; p = new char; strcpy(p, &quot;june&quot;); cout &lt;&lt; p &lt;&lt; endl; p = new char; strcpy(p, &quot;august&quot;); cout &lt;&lt; p &lt;&lt; endl; p = new...

Создание матрицы и сортировка, используя несколько функций - C++
Доброго времени суток, всем пользователям. Нуждаюсь в помощи, имею код, в котором лишь используется 1 функция int main (); Но согласно...


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

Или воспользуйтесь поиском по форуму:
30
Ответ Создать тему
Опции темы

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