Заимствование Пример Говарда Хиннанта и изменение его для использования копирования и обмена, это op = thread-safe?
struct A {
A() = default;
A(A const &x); // Assume implements correct locking and copying.
A& operator=(A x) {
std::lock_guard<std::mutex> lock_data (_mut);
using std::swap;
swap(_data, x._data);
return *this;
}
private:
mutable std::mutex _mut;
std::vector<double> _data;
};
Я полагаю, что этот потокобезопасный (помните, что параметр op = передается по значению), и единственная проблема, которую я могу найти, это та, что скрыта под ковриком: копия ctor. Тем не менее, это будет редкий класс, который разрешает копирование-назначение, но не копирование-построение, поэтому проблема существует одинаково в обеих альтернативах.
Учитывая, что самопредставление настолько редко (по крайней мере, для этого примера), что я не возражаю против дополнительной копии, если это произойдет, считаю потенциальную оптимизацию этого! = & Rhs либо незначительной, либо пессимизацией. Будет ли какая-либо другая причина предпочитать или избегать этого по сравнению с оригинальной стратегией (ниже)?
A& operator=(A const &rhs) {
if (this != &rhs) {
std::unique_lock<std::mutex> lhs_lock( _mut, std::defer_lock);
std::unique_lock<std::mutex> rhs_lock(rhs._mut, std::defer_lock);
std::lock(lhs_lock, rhs_lock);
_data = rhs._data;
}
return *this;
}
Между прочим, я думаю, что это кратко обрабатывает копию ctor, по крайней мере, для этого класса, даже если это немного тупо:
A(A const &x) : _data {(std::lock_guard<std::mutex>(x._mut), x._data)} {}