提问人:The amateur programmer 提问时间:10/15/2023 更新时间:10/15/2023 访问量:23
在 C++03 编译器上使用移动仿真将 boost::unique_lock 作为返回值移出函数是否安全?
Is it safe to move boost::unique_lock out of a function as a return value using move emulation on C++03 compiler?
问:
我有一个可移动但不可复制的类,可用于同步对某些共享资源的访问:
class wrapper_with_lock{
private:
BOOST_MOVABLE_BUT_NOT_COPYABLE(wrapper_with_lock)
boost::unique_lock l;
public:
int* data1;//These point to data that needs to have synchronized access
char* data2;//....
wrapper_with_lock(boost::mutex& m) : l(m){}//Constructor acquires the lock
wrapper_with_lock(BOOST_RV_REF(wrapper_with_lock) x) {
l = boost::move(x.l);//Move the lock
data1 = x.data1;//Move the pointers
x.data1 = 0;
....
}
wrapper_with_lock& operator=(BOOST_RV_REF(wrapper_with_lock) x) // Move assign
{
if (this != &x){
l = boost::move(x.l);//Move the lock and other data
....
}
return *this;
}
}
这里的想法是,这个结构可以四处移动,握住互斥锁,它会在超出范围后自动释放锁。预期用途如下:
wrapper_with_lock do_some_init(boost::mutex& m){
wrapper_with_lock w(m);
*(w.data1) = 1234;//Do something initially with the data etc...
//Return the lock holding object by moving it (should move the internal lock).
//The lock should be valid and properly moved to the caller
//of this function inside the wrapper
return boost::move(w);
}
问题是,当我们在这个项目中坚持使用 C++ 编译器的 boost 库的移动仿真时,这种移动锁的需要行为是否得到保证?旧编译器不支持较新的标准。
答:
1赞
sehe
10/15/2023
#1
是的。以下是您自己验证的方法:
#include <boost/move/move.hpp>
#include <boost/thread.hpp>
#include <boost/thread/locks.hpp>
class wrapper_with_lock {
private:
BOOST_MOVABLE_BUT_NOT_COPYABLE(wrapper_with_lock)
boost::unique_lock<boost::mutex> l;
public:
int* data1; // These point to data that needs to have synchronized access
char* data2; //....
~wrapper_with_lock() {
delete[] data1;
delete[] data2;
}
wrapper_with_lock(boost::mutex& m)
: l(m)
, data1(new int[1024])
, data2(new char[1024]) {} // Constructor acquires the lock
wrapper_with_lock(BOOST_RV_REF(wrapper_with_lock) x) {
bool was_locked = x.locked();
assert(was_locked); // actually invariant of wrapper_with_lock?
l = boost::move(x.l); // Move the lock
assert(!x.locked());
assert(was_locked == locked());
data1 = x.data1; // Move the pointers
x.data1 = 0;
data2 = x.data2; // Move the pointers
x.data2 = 0;
}
bool locked() const { return l.owns_lock(); }
wrapper_with_lock& operator=(BOOST_RV_REF(wrapper_with_lock) x) // Move assign
{
if (this != &x) {
bool was_locked = x.locked();
assert(was_locked); // actually invariant of wrapper_with_lock?
l = boost::move(x.l); // Move the lock and other data
assert(!x.locked());
assert(was_locked == locked());
//....
data1 = x.data1; // Move the pointers
x.data1 = 0;
data2 = x.data2; // Move the pointers
x.data2 = 0;
}
return *this;
}
};
wrapper_with_lock do_some_init(boost::mutex& m){
wrapper_with_lock w(m);
*w.data1 = 1234; // Do something initially with the data etc...
// Return the lock holding object by moving it (should move the internal lock).
// The lock should be valid and properly moved to the caller
// of this function inside the wrapper
return boost::move(w);
}
int main() {
boost::mutex m;
wrapper_with_lock l = do_some_init(m);
assert(l.locked());
}
评论
1赞
sehe
10/15/2023
没什么,我建议让所有权更容易、更安全(仍然是 c++03:coliru.stacked-crooked.com/a/1a56c46b8d2f9002)。在那个阶段,我很难看出锁增加了什么。由于资源无论如何都是唯一的所有权,只要不共享引用,就永远不会出现数据竞争。根据定义,锁仍然可以共享引用,因此锁不会保护任何东西: coliru.stacked-crooked.com/a/0266fe8f89eb831c - 更少的代码,更高的性能,没有泄漏,仍然是 c++03
1赞
The amateur programmer
10/15/2023
用例比仅仅传递单个值要复杂得多,这个旧的代码库还有很多其他的东西也需要同步(在众多线程之间共享),并且不能使它唯一,但对于这个想法来说+1。
评论