Скрыть Boost::mutex из интерфейса DLL из блокируемого контейнера
Я использовал Boost в проекте DLL, но не экспортировал какие-либо зависимости Boost... пока. Просто C-типы и вещи, которые происходят от самого дерева исходного кода DLL.
Но сейчас я борюсь с блокируемой моделью данных... Я не могу создать безопасную исключительную ситуацию и не направлять типы форсирования экспорта в интерфейс DLL.
struct DLL_EXPORT DllTestData {
double test1;
double test2;
void lock();
void unlock();
DllTestDataLock getGuard();
boost::mutex;
}
И использовать это:
DllTestData ptr;
ptr->lock();
ptr->test1 = 1.0;
ptr->unlock();
Можно, по крайней мере, спроектировать что-то вроде DllTestData::Pimpl и скрыть тип мьютекса от Dll. Но если я хочу использовать это так:
DllTestData ptr;
{
auto g = ptr->getGuard();
ptr->test1 = 1.0;
}
При написании этого я начинаю думать о ILockable-Interface и скрывать тип мьютекса в PImpl или что-то в этом роде, так что-то вроде этого:
struct ILockable {
void lock() = 0;
void unlock() = 0;
}
struct DLL_EXPORT DllTestData : public struct ILockable {
/// ...
private:
class PImpl;
Pimpl * impl;
}
struct Guard {
Guard( ILockable * ptr ) {
ptr->lock();
}
~Guard() {
ptr->unlock();
}
}
И используйте это так:
DllTestData ptr = fromDll();
{
Guard g(ptr);
ptr->test1 = 1.0;
}
Будет ли это правильным подходом (скрыть мьютексный тип с помощью pimpl и работать с блокируемым интерфейсом) или я иду в неверном направлении с этим? Или что будет работать лучше в этом сценарии? Может быть, переместить весь boost::mutex PImpl в интерфейс?
1 ответ
Да, по-моему, вы на правильном пути. Но ваша структура настолько "тяжелая", что вы должны экспортировать ее как интерфейс с методом get и set значений вместо самих значений. Если вы используете фабричный шаблон, одну функцию для создания объекта и одну для удаления, вы можете безопасно получать данные из интерфейса внутри вашей dll, даже не выставляя противный Pimpl * impl.
Глядя на это снова, вы можете вообще не подвергать мьютекс. Например, если только оба значения должны быть установлены одновременно, выставьте
void setValues(double test1,double test2);
внутри метода вы можете установить мьютекс самостоятельно. Или более классический подход Win32, если вы не хотите большого списка get и set: предоставьте структуру без какого-либо метода, такого как:
struct DLLTestData
{
double test1;
double test2;
// …and as many as you want
};
и добавить функцию или метод в ваш экспорт, как
void setTestData(DLLTestData value);
внутри вашей библиотеки вы можете заблокировать и запомнить всю структуру. Как было сказано ранее, я привык ко второму способу при интенсивном использовании Win32 API, но лично я предпочитаю первый подход с интерфейсом и get/setter, даже если это требует больше усилий.