Здравствуйте.
Понадобилось мне в нескольких независимых местах блокировать разные ресурсы на чтение/запись. Написал такую штуку:
#ifndef LOCKER_H
#define LOCKER_H
template<int magic>
class Locker
{
public:
Locker(bool write)
{
init();
m_write = write;
if (!m_write)
{
WaitForSingleObject(mutex, INFINITE);
if (!readers)
{
ResetEvent(event);
}
InterlockedIncrement(&readers);
ReleaseMutex(mutex);
}
else
{
HANDLE h[] = {event, mutex};
WaitForMultipleObjects(2, h, TRUE, INFINITE);
}
}
~Locker()
{
WaitForSingleObject(mutex, INFINITE);
if (!m_write)
{
InterlockedDecrement(&readers);
if (!readers)
{
SetEvent(event);
}
}
else
{
ReleaseMutex(mutex);
}
ReleaseMutex(mutex);
};
private:
void init()
{
if (!first) return;
first = false;
mutex = CreateMutex(NULL, FALSE, NULL);
event = CreateEvent(NULL, TRUE, TRUE, NULL);
}
static bool first;
static HANDLE mutex;
static HANDLE event;
static LONG readers;
bool m_write;
};
template<int magic>
bool Locker<magic>::first = true;
template<int magic>
HANDLE Locker<magic>::mutex = NULL;
template<int magic>
HANDLE Locker<magic>::event = NULL;
template<int magic>
LONG Locker<magic>::readers = 0;
#endif //LOCKER_H
Пример использования:
typedef Locker<123> Resource1Locker;
typedef Locker<456> Resource2Locker;
.....
void func1()
{
Resource1Locker lock(false);
// теперь первый ресурс можно безболезненно читать, его не изменят до конца функции
}
void func2()
{
Resource2Locker lock(true);
// теперь второй ресурс можно безболезненно изменять, его не будут читать до конца функции
}
Просто, понятно, работает (!)... Компилится в VC6 (!!). Единственное слабое место — код инициализации
. Но тут уж ничего не поделаешь (если кто-то знает способ — опубликуйте, буду благодарен).. Параноикам могу предложить перед началом создовать по штуке объектов каждого класса, тогда этой проблемы не будет. Лично я не настолько параноик, предпочитаю надеяться на лучшее