Не возникнет ли гонка данных?
Суть в том, что чтение из одного блока данных происходит очень часто из разных потоков, но в определенный момент один(заранее заданный поток) может обновить данные, так как код используется в очень критичном месте и обновление данных происходит очень быстро, никакой блокировки с засыпанием быть не должно (mutex, shared_mutex). Написал свой велосипед:
Сама структура:
struct BufferData {
...
volatile std::atomic<bool> m_remapFlag{false}; //флаг, если происходит запись
volatile std::atomic<std::size_t> m_usageCounter{0}; //количество чтений
};
Блокировка/освобождение на чтение (блокировка на чтение не должно блокировать другое чтение):
BufferData *OGLBuffer::lock() {
std::shared_ptr<BufferData> ptr;
if (!m_data.expired()) {
ptr = m_data.lock();
} else
throw std::runtime_error("Buffer page deleted");
//Ждем пока обновляют данные
while (ptr->m_remapFlag) {
continue;
}
//Увеличиваем счетчик
ptr->m_usageCounter++;
if (!ptr->m_remapFlag) {
//Если за это время не начали обновлять данные то возвращаем указатель
return ptr.get();
} else {
//Иначе повторяем попытку
unlock();
return lock();
}
//Метод освобождения довольно прост
void OGLBuffer::unlock() { m_data.lock()->m_usageCounter--; }
Теперь блокировка/освобождение на запись:
void OGLPage::lockBuffer(std::size_t const &id) {
m_buffers[id]->m_remapFlag = true; //Ставим флаг на запись
//Ждем конца чтений
while (m_buffers[id]->m_usageCounter > 0) {
continue;
}
}
void OGLPage::unlockBuffer(std::size_t const &id) {
//Чистим флаг
m_buffers[id]->m_remapFlag = false;
}
Вроде бы не вижу мест где гонка могла бы возникнуть, однако доказать что так и есть, увы, не могу. Хотелось бы услышать комментариев/критики по этому поводу.