Нет, это не правильно. Вы почти у цели, но большая проблема в том, что функции умножения и приращения должны использовать тот же мьютекс , что и .
Мьютекс - это объект, обеспечивающий исключение MUTual. Другими словами, цель мьютекса состоит в том, чтобы предотвратить одновременное прикосновение двух потоков к одной и той же переменной и вызвать непредсказуемые результаты. Мьютекс - это своего рода токен, который удерживает один поток за раз, что дает ему «право» на доступ к определенной переменной (или набору переменных). В этом случае переменная, которую вы пытаетесь защитить, равна counter
. Должен быть один и только один мьютекс, который контролирует право доступа counter
. В вашем случае каждый поток будет иметь свой собственный токен, который, по его мнению, дает ему право на доступ к счетчику, и поэтому будет непредсказуемое поведение.
Вы "держите" мьютекс, блокируя его. В этом смысл замков, и поэтому вы не можете их «избежать». Весь смысл блокируемых областей состоит в том, что, если у вас есть только один мьютекс m
, когда один из потоков удерживает блокировку на m
, другой поток гарантированно не будет удерживать блокировку на m
. Если вы правильно закодировали, удержание блокировки на m
должно быть предварительным условием для доступа к counter
, и поэтому значение counter
должно быть предсказуемым.
Теперь по поводу wait()
. Вызов wait()
означает «Я снимаю блокировку этого мьютекса, пока кто-то другой не сигнализирует об этом условии, и затем я хочу вернуть его». Тем временем поток останавливается. Таким образом, при условии, что у вас есть только один мьютекс m
и условие c
, а lk
- это блокировка m
, строка c.wait(lk)
означает, что поток откажется от блокировки lk
при m
и затем приостановите выполнение, пока какой-нибудь другой поток не вызовет c.notify_one()
(или c.notify_all()
). Когда ожидающий поток вернется из вызова на wait()
, он автоматически повторно получит блокировку lk
на m
и, таким образом, снова получит доступ к counter
.
Наконец, эти повышающие блокировки являются «ограниченными». Это означает, что они освобождаются автоматически при уничтожении (когда они выходят за рамки). Таким образом, в этом случае каждая функция удерживает свою блокировку до тех пор, пока она не выйдет, за исключением случаев, когда она отдает свою блокировку для ожидания и приостанавливает выполнение в ожидании сигнала.