Блокировка std :: mutex зависает при переопределении нового оператора
У нас есть менеджер внутренней памяти, который мы используем с одним из наших продуктов. Менеджер памяти переопределяетnew
а такжеdelete
операторы, и отлично работает в однопоточных приложениях. Однако я'Теперь мне поручено заставить его работать и с многопоточными приложениями. Насколько я понимаю, следующий псевдокод должен работать, но он висит на спине, даже сtry_lock()
, Есть идеи?
Обновление № 1
Причины "Нарушение доступа":
#include
std::mutex g_mutex;
/*!
\brief Overrides the Standard C++ new operator
\param size [in] Number of bytes to allocate
*/
void *operator new(size_t size)
{
g_mutex.lock(); // Access violation exception
...
}
Заставляет нить зависать навсегда в спине:
#include
std::mutex g_mutex;
bool g_systemInitiated = false;
/*!
\brief Overrides the Standard C++ new operator
\param size [in] Number of bytes to allocate
*/
void *operator new(size_t size)
{
if (g_systemInitiated == false) return malloc(size);
g_mutex.lock(); // Thread hangs forever here. g_mutex.try_lock() also hangs
...
}
int main(int argc, const char* argv[])
{
// Tell the new() operator that the system has initiated
g_systemInitiated = true;
...
}
Обновление № 2
Рекурсивный мьютекс также заставляет нить зависать навсегда в спине:
#include
std::recursive_mutex g_mutex;
bool g_systemInitiated = false;
/*!
\brief Overrides the Standard C++ new operator
\param size [in] Number of bytes to allocate
*/
void *operator new(size_t size)
{
if (g_systemInitiated == false) return malloc(size);
g_mutex.lock(); // Thread hangs forever here. g_mutex.try_lock() also hangs
...
}
int main(int argc, const char* argv[])
{
// Tell the new() operator that the system has initiated
g_systemInitiated = true;
...
}
Обновление № 3
Джонатан Уэйкли предложил мне попробоватьunique_lock
и / илиlock_guard
, но замок все еще висит в спине.
unique_lock
тестовое задание:
#include
std::mutex g_mutex;
std::unique_lock g_lock1(g_mutex, std::defer_lock);
bool g_systemInitiated = false;
/*!
\brief Overrides the Standard C++ new operator
\param size [in] Number of bytes to allocate
*/
void *operator new(size_t size)
{
if (g_systemInitiated == false) return malloc(size);
g_lock1.lock(); // Thread hangs forever here the first time it is called
...
}
int main(int argc, const char* argv[])
{
// Tell the new() operator that the system has initiated
g_systemInitiated = true;
...
}
lock_guard
тестовое задание:
#include
std::recursive_mutex g_mutex;
bool g_systemInitiated = false;
/*!
\brief Overrides the Standard C++ new operator
\param size [in] Number of bytes to allocate
*/
void *operator new(size_t size)
{
if (g_systemInitiated == false) return malloc(size);
std::lock_guard g_lock_guard1(g_mutex); // Thread hangs forever here the first time it is called
...
}
int main(int argc, const char* argv[])
{
// Tell the new() operator that the system has initiated
g_systemInitiated = true;
...
}
Я думаю, что моя проблема в том, чтоdelete
вызывается библиотекой мьютексов C ++ 11 при блокировке.delete
также переопределяется так:
/*!
\brief Overrides the Standard C++ new operator
\param p [in] The pointer to memory to free
*/
void operator delete(void *p)
{
if (g_systemInitiated == false)
{
free(p);
}
else
{
std::lock_guard g_lock_guard1(g_mutex);
...
}
}
Это вызывает тупиковую ситуацию, которую я могуя не вижу хорошего решения, кроме как сделать свою собственную блокировку, которая не порождает никаких вызововnew
или жеdelete
во время блокировки или разблокировки.
Обновление № 4I '
я реализовал свой собственный рекурсивный мьютекс, который не имеет вызововnew
или жеdelete
Кроме того, он позволяет тому же потоку войти в заблокированный блок.
#include
std::thread::id g_lockedByThread;
bool g_isLocked = false;
bool g_systemInitiated = false;
/*!
\brief Overrides the Standard C++ new operator
\param size [in] Number of bytes to allocate
*/
void *operator new(size_t size)
{
if (g_systemInitiated == false) return malloc(size);
while (g_isLocked && g_lockedByThread != std::this_thread::get_id());
g_isLocked = true; // Atomic operation
g_lockedByThread = std::this_thread::get_id();
...
g_isLocked = false;
}
/*!
\brief Overrides the Standard C++ new operator
\param p [in] The pointer to memory to free
*/
void operator delete(void *p)
{
if (g_systemInitiated == false)
{
free(p);
}
else
{
while (g_isLocked && g_lockedByThread != std::this_thread::get_id());
g_isLocked = true; // Atomic operation
g_lockedByThread = std::this_thread::get_id();
...
g_isLocked = false;
}
}
int main(int argc, const char* argv[])
{
// Tell the new() operator that the system has initiated
g_systemInitiated = true;
...
}
Обновление № 5
Попробовал предложение Джонатана Уэйкли и обнаружил, что определенно кажется, что с Microsoft что-то не так ».s реализация C ++ 11 Mutexes; его пример зависает, если скомпилирован с/MTd
(Многопоточный отладочный) флаг компилятора, но работает нормально, если скомпилирован с/MDd
(Многопоточный Debug DLL) флаг компилятора. Как справедливо указал Джонатанstd::mutex
реализации должны бытьconstexpr
s. Вот код VS 2012 C ++, который я использовал для проверки проблемы реализации:
#include "stdafx.h"
#include
#include
bool g_systemInitiated = false;
std::mutex g_mutex;
void *operator new(size_t size)
{
if (g_systemInitiated == false) return malloc(size);
std::lock_guard lock(g_mutex);
std::cout < "Inside new() critical section" < std::endl;
//