Скрыть 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, даже если это требует больше усилий.

Другие вопросы по тегам