c, c ++ память в общих библиотеках

Я не уверен, как статическая глобальная память управляется в DLL и общих объектах. Я не знаю, каждый ли обрабатывает это одинаково или по-разному на разных платформах.

Предположим, у вас есть библиотека классов, один из этих классов является классом мьютекса, и другие классы в библиотеке будут использовать этот мьютекс. Каков наилучший или самый безопасный способ размещения мьютекса в библиотеке? Я вижу пару вариантов:

  1. Сделайте мьютекс приватным в классе. Это я не вижу работы, потому что жизнь мьютекса будет действительна только в течение жизни объекта. Может быть, сделать объект одиночным и инициализировать его при загрузке библиотеки (с помощью dllattach или атрибут((конструктор))) будет работать, я не уверен.

  2. Выделите мьютекс вне класса в статическом глобальном пространстве библиотеки. Я думаю, что это будет лучшим вариантом, но что именно происходит при загрузке DLL? Если я сделал объект статическим и глобальным в библиотеке, когда он будет выделен, где в программе он будет выделен? Что произойдет, если библиотека загружается во время выполнения, а не при запуске программы?

Любая информация об этом с благодарностью!

1

Решение

Способ управления памятью в общих образах зависит от конкретных платформ, а библиотеки DLL зависят от Microsoft Windows.

В общем-то, Вы всегда должны избегать использования глобальных / общих статических переменных, поскольку они могут привести к серьезным проблемам или ошибкам, которые трудно идентифицировать или устранить. Даже синглтон-классы могут вызвать несколько проблем в C ++, особенно в библиотеках или многопоточных приложениях. (И вообще, используя синглтоны не считаются хорошими даже на языках более высокого уровня.)

Для защиты от условий взаимного исключения гонок лучшим вариантом будет использование замковый замок класс реализован с использованием RAII техника, рядом с shared_ptr умный указатель, который автоматизирует выделение и удаление памяти.

Код ниже иллюстрирует реализацию Mutex с помощью Windows API и вышеуказанных методов (а также Идиома):

// Mutex.h
#pragma once
#include <memory>

class Mutex
{
public:
typedef unsigned long milliseconds;

Mutex();
~Mutex();

void Lock();
void Unlock();
bool TryLock();
bool TimedLock(milliseconds ms);

private:
struct private_data;
std::shared_ptr<private_data> data;
// Actual data is hold in private_data struct which is non-accessible.
// We only hold a "copyable handle" to it through the shared_ptr, which
// prevents copying this "actual data" object by, say, assignment operators.
// So, private_data's destructor automatically gets called only when the last
// Mutex object leaves its scope.
};

// Mutex.cpp
#include "Mutex.h"#include <windows.h>

struct Mutex::private_data
{
HANDLE hMutex;

private_data()
{
hMutex = CreateMutex(NULL, FALSE, NULL);
}

~private_data()
{
// Unlock(); ?? :/
CloseHandle(hMutex);
}
};

Mutex::Mutex()
: data (new private_data())
{ }

Mutex::~Mutex()
{ }

void Mutex::Lock()
{
DWORD ret = WaitForSingleObject(data->hMutex, INFINITE);
ASSERT(ret == WAIT_OBJECT_0);
}

void Mutex::Unlock()
{
ReleaseMutex(data->hMutex);
}

bool Mutex::TryLock()
{
DWORD ret = WaitForSingleObject(data->hMutex, 0);

ASSERT(ret != WAIT_ABANDONED);
ASSERT(ret != WAIT_FAILED);

return ret != WAIT_TIMEOUT;
}

bool Mutex::TimedLock(milliseconds ms)
{
DWORD ret = WaitForSingleObject(data->hMutex, static_cast<DWORD>(ms));

ASSERT(ret != WAIT_ABANDONED);
ASSERT(ret != WAIT_FAILED);

return ret != WAIT_TIMEOUT;
}

// ScopedLock.h
#pragma once
#include "Mutex.h"
class ScopedLock
{
private:
Mutex& m_mutex;

ScopedLock(ScopedLock const&);             // disable copy constructor
ScopedLock& operator= (ScopedLock const&); // disable assignment operator

public:
ScopedLock(Mutex& mutex)
: m_mutex(mutex)
{ m_mutex.Lock(); }

~ScopedLock()
{ m_mutex.Unlock(); }
};

Пример использования:

Mutex m1;
MyClass1 o1;
MyClass2 o2;
...

{
ScopedLock lock(m1);

// thread-safe operations
o1.Decrease();
o2.Increase();

} // lock is released automatically here upon leaving scope

// non-thread-safe operations
o1.Decrease();
o2.Increase();

Хотя приведенный выше код даст вам основную идею, даже лучший вариант — использовать высококачественные библиотеки C ++, такие как увеличение, который имеет mutex, scoped_lock и многие другие классы уже доступны. (К счастью, C ++ 11 полностью охватывает классы синхронизации, освобождая вас от необходимости использовать библиотеки повышения.)

ОБНОВИТЬ:
Я предлагаю вам поискать темы об автоматической сборке мусора в C ++, а также о методике RAII.

2

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector