Ответ зависит от класса.Если методы не имеют общего доступа к одним и тем же переменным экземпляра, синхронизация не требуется.Это связано с тем, что механизм вызова метода по своей сути поточно-ориентирован, поскольку не изменяет объект.Если они имеют общий доступ, вам нужна синхронизация.Возьмем, к примеру, этот класс:
class A
{
public:
void inc () { x++; }
void dec () { x--; }
private:
int x;
};
Если нескольким потокам разрешено вызывать методы А одновременно, вам нужно защитить x с помощью мьютекса.Есть несколько возможных стратегий.Один из них - сделать класс потокобезопасным.Это выглядело бы так:
class A
{
public:
void inc () {
m.lock();
x++;
m.unlock();
}
void dec () {
m.lock();
x--;
m.unlock();
}
private:
int x;
mutex m;
};
Преимущество здесь в том, что звонящим не нужно беспокоиться о синхронизации.Недостатком является снижение производительности, если класс вызывается только из одного потока.У вас также есть проблема, если вам нужно гарантировать, что поток может вызывать несколько методов подряд без вмешательства другого потока.В этом случае вызывающему потоку необходимо посмотреть класс перед его использованием.Это выглядело бы так:
class A
{
public:
void lock () { m.lock(); }
void unlock () { m.unlock(); }
void inc () { x++; }
void dec () { x--; }
private:
int x;
mutex m;
};
Затем вызывающие абоненты должны обернуть вызовы метода в пару A :: lock () / A :: unlock ().Если вам нужно использовать класс, который не был написан с учетом безопасности потоков, вам нужно создать мьютекс вне объекта и использовать его, как в предыдущем примере.Или вы можете создать потокобезопасную оболочку.Недостатком, конечно, является то, что это подвержено ошибкам.
Обратите внимание, что вы также можете предложить как заблокированный, так и разблокированный доступ:
class A
{
public:
void lock () { m.lock(); }
void unlock () { m.unlock(); }
void inc_unlocked () { x++; }
void dec_unlocked () { x--; }
void inc () { m.lock(); inc_unlocked(); m.unlock(); }
void dec () { m.lock(); dec_unlocked(); m.unlock(); }
private:
int x;
mutex m;
};
Таким образом, если класс используется в одном потокеПриложение использует разблокированные версии для производительности, в противном случае вы используете либо заблокированные версии, либо разблокированные версии, включенные в вызовы lock () / unlock ().Это лучшее из обоих миров за счет увеличения сложности.
Выбор между этими вариантами - дело вкуса и опыта.