Мьютекс - это то, что вы захватываете, и останавливает любые другие потоки, пытающиеся захватить его, пока вы не освободите его из потока захвата.
В вашем вопросе у вас есть функция f, выделяющая экземпляр Mutex. Этого недостаточно, чтобы заблокировать это. Вы должны специально вызывать mutex.lock () (в Qt, но также и в целом, если только вы не используете pthread, в этом случае используйте pthread_mutex_lock и получайте удовольствие от низкоуровневых, зависящих от платформы вещей. Qt очень хорошо его абстрагирует).
вот пример с Qt
void MyClass::doStuff( int c )
{
mutex.lock();
a = c;
b = c * 2;
mutex.unlock();
}
Как только вы получите блокировку, вызов g () будет сделан из потока, который получил блокировку, поэтому он будет один в этом вызове , предполагая , что вы не вызываете g () из другие потоки из другой части кода. Блокировка не означает, что она остановит все остальные потоки. Это остановит потоки, пытающиеся получить такую же блокировку, пока блокировка не будет снята.
Если это единственный способ для ваших потоков достичь g (), то вы синхронизированы с этим доступом.
Что касается второй части вашего вопроса: если мьютекс является атрибутом экземпляра, то это будут два разных мьютекса. Вам придется объявить и создать экземпляр экземпляра мьютекса класса и сослаться на него для блокировки. В этом случае любая попытка вызвать метод в классе, который блокирует мьютекс класса, будет эффективно синхронизирована, что означает, что никакие два потока не будут выполнять этот метод вместе.
Например (у меня нет Qt, поэтому я не могу скомпилировать этот код, и я перестал его кодировать 2 года назад, поэтому он не мог работать)
class Foo {
public:
void method(void) {
mutex.lock();
cout << "method called";
// long computation
mutex.unlock();
}
private:
QMutex mutex;
};
Хорошо, в этом случае предположим, что у вас есть два потока, 1 и 2, и два экземпляра класса Foo, a и b. Предположим, что поток 1 вызывает a.method (), а поток 2 вызывает b.method (). В этом случае два взаимных исключения являются разными экземплярами, поэтому каждый поток будет выполнять вызов независимо и работать параллельно.
Предположим, у вас есть два потока, 1 и 2, и один экземпляр класса Foo, который совместно используется двумя потоками. если поток 1 вызывает a.method (), а затем поток 2 вызывает a.method (), поток 2 остановится и будет ожидать освобождения блокировки мьютекса.
Наконец,
class Foo {
public:
void method(void) {
mutex.lock();
cout << "method called";
// long computation
mutex.unlock();
}
private:
static QMutex mutex;
};
QMutex Foo::mutex;
В этом случае мьютекс является статической переменной класса. У вас есть только один экземпляр мьютекса для каждого экземпляра объекта. Предположим, у вас была та же ситуация, что и в первом случае выше: два потока и два экземпляра. В этом случае, когда второй поток пытается вызвать b.method (), он должен будет дождаться завершения a.method () первым потоком, поскольку блокировка теперь уникальна и используется всеми экземплярами вашего класса.
Для получения дополнительной информации, у Qt есть хорошее руководство по многопоточности
https://doc.qt.io/qt-5/threads.html