С учетом следующего C-API, внутренне реализованного в C ++
struct OpaqueObject;
struct OpaqueObject *allocateObject();
int deallocateObject(struct OpaqueObject *obj);
int useObject(struct OpaqueObject *obj);
Безопасно распределять, использовать и освобождать несколько отдельных struct OpaqueObject
-экземпляров одновременно.Конечно, одновременное использование одного struct OpaqueObject
-Instance недопустимо и приведет к неопределенному поведению.В качестве гарантии struct OpaqueObject
содержит мьютекс, запрещающий именно эту ситуацию: функция useObject()
возвращается с кодом ошибки, если несколько потоков пытаются вызвать его с одним и тем же struct OpaqueObject
-Instance.
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()
, либо в * 1020?*, если эти функции использовались одновременно с одним и тем же struct OpaqueObject
-Instance?