Простой способ сделать класс потокобезопасным - это добавить атрибут мьютекса и заблокировать мьютекс в методах доступа
class cMyClass {
boost::mutex myMutex;
cSomeClass A;
public:
cSomeClass getA() {
boost::mutex::scoped_lock lock( myMutex );
return A;
}
};
Проблема в том, что это делает класс не копируемым.
I может заставить все работать, сделав мьютекс статическим. Однако это означает, что каждый экземпляр класса блокируется при обращении к любому другому экземпляру, потому что все они используют один и тот же мьютекс.
Интересно, есть ли лучший способ?
Я пришел к выводу, что нет лучшего путь. Сделать класс потокобезопасным с помощью атрибута private static mutex «лучше всего»: это просто, это работает и скрывает неудобные детали.
class cMyClass {
static boost::mutex myMutex;
cSomeClass A;
public:
cSomeClass getA() {
boost::mutex::scoped_lock lock( myMutex );
return A;
}
};
Недостатком является то, что все экземпляры класса совместно используют один и тот же мьютекс и, таким образом, излишне блокируют друг друга. Это нельзя исправить, сделав атрибут мьютекса нестатическим (таким образом, предоставив каждому экземпляру свой собственный мьютекс), потому что сложности копирования и присвоения кошмарны, если все сделано правильно.
Отдельные мьютексы, если требуется, должны управляться внешний некопируемый синглтон со ссылками на каждый экземпляр при создании.
Спасибо за все ответы.
Несколько человек упомянули о написании моего собственного конструктора копирования и оператора присваивания. Я пробовал это. Проблема в том, что у моего реального класса много атрибутов, которые всегда меняются в процессе разработки. Поддержание конструктора копирования и оператора assignmet утомительно и чревато ошибками, из-за чего ошибки трудно найти. Разрешение компилятору генерировать их для сложного класса - это огромная экономия времени и устранение ошибок.
Во многих ответах говорится о том, как сделать конструктор копирования и оператор присваивания потокобезопасным. Это требование добавляет ко всему этому еще больше сложности! К счастью для меня, мне это не нужно, так как все копирование выполняется во время установки в одном потоке.
class cSafe {
boost::mutex myMutex;
cSomeClass A;
public:
cSomeClass getA() {
boost::mutex::scoped_lock lock( myMutex );
return A;
}
(copy constructor)
(assignment op )
};
class cMyClass {
cSafe S;
( ... other attributes ... )
public:
cSomeClass getA() {
return S.getA();
}
};