考虑到在C ++内部实现了以下C-API
struct OpaqueObject;
struct OpaqueObject *allocateObject();
int deallocateObject(struct OpaqueObject *obj);
int useObject(struct OpaqueObject *obj);
同时分配,使用和取消分配几个不同的struct OpaqueObject
- 实例是安全的。当然,不允许同时使用一个struct OpaqueObject
- 实例,并且会产生未定义的行为。作为安全措施,struct OpaqueObject
包含一个互斥锁,禁止这种情况:函数useObject()
返回错误代码,如果多个线程尝试使用相同的struct OpaqueObject
- 实例调用它。
struct OpaqueObject {
std::mutex access;
// ...
};
int useObject(struct OpaqueObject *obj) {
if (!obj->access.try_lock()) {
// different thread currently uses this obj
return CONCURRENT_USE_ERROR;
} else {
// start using this obj
// ...
obj->access.unlock();
return OK;
}
}
但是,这种保障机制如何扩展到功能deallocateObject()
?第一个天真的方法是
int deallocateObject(struct OpaqueObject *obj) {
if (!obj->access.try_lock()) {
// different thread currently uses this obj
return CONCURRENT_USE_ERROR;
} else {
delete obj; // <--- (1)
return OK;
}
}
但是当它仍然被锁定时,销毁互斥锁是不明确的行为。我们无法在第(1)
行之前解锁它,因为这会完全阻止我们阻止并发使用和释放的努力。
是否可以在useObject()
或deallocateObject()
中返回错误,如果这些函数与同一struct OpaqueObject
- 实例同时使用?
答案 0 :(得分:1)
您可以将std::mutex
与std::atomic<int>
交换:
struct OpaqueObject {
std::atomic<int> access = 0;
// ...
};
然后在您的函数中,您可以自动交换值并查看它是否正在使用中:
int useObject(struct OpaqueObject *obj) {
if (obj->access.exchange(1)) {
// different thread currently uses this obj
return CONCURRENT_USE_ERROR;
} else {
// start using this obj
// ...
obj->access.exchange(0);
return OK;
}
}
如果对象在使用变量access
= 1且std::atomic::exchange
将返回1.否则返回0并将access
设置为1.
同样删除该对象也可以。
int deallocateObject(struct OpaqueObject *obj) {
if (obj->access.exchange(1)) { // (*)
// different thread currently uses this obj
return CONCURRENT_USE_ERROR;
} else {
delete obj; // (**)
return OK;
}
}
重要提示:您是否考虑过删除对象后发生的事情?你如何通知其他线程删除它?