我们有一个与我们的产品之一一起使用的内部内存管理器。内存管理器覆盖new
and delete
运算符,并且在单线程应用程序中运行良好。然而,我现在的任务是让它也适用于多线程应用程序。据我了解,以下伪代码应该可以工作,但即使使用try_lock()
。有任何想法吗?
更新#1
导致“访问冲突”的原因:
#include <mutex>
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 <mutex>
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 <mutex>
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
and/or lock_guard
,但锁仍然处于旋转状态。
unique_lock
test:
#include <mutex>
std::mutex g_mutex;
std::unique_lock<std::mutex> 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
test:
#include <mutex>
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<std::mutex> 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<std::mutex> g_lock_guard1(g_mutex);
...
}
}
这会导致死锁情况,除了进行自己的锁定不会产生任何调用之外,我看不到任何好的解决方案new
or delete
锁定或解锁时。
更新#4
我已经实现了自己的自定义递归互斥体,没有调用new
or delete
此外,它还允许同一线程进入锁定块。
#include <thread>
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
尝试了 Jonathan Wakely 的建议,发现微软对 C++ 11 Mutexes 的实现肯定有问题;如果使用以下命令编译,他的示例将挂起/MTd
(多线程调试)编译器标志,但如果使用/MDd
(多线程调试DLL)编译器标志。正如乔纳森正确指出的那样std::mutex
实施应该是constexpr
的。这是我用来测试实现问题的 VS 2012 C++ 代码:
#include "stdafx.h"
#include <mutex>
#include <iostream>
bool g_systemInitiated = false;
std::mutex g_mutex;
void *operator new(size_t size)
{
if (g_systemInitiated == false) return malloc(size);
std::lock_guard<std::mutex> lock(g_mutex);
std::cout << "Inside new() critical section" << std::endl;
// <-- Memory manager would be called here, dummy call to malloc() in stead
return malloc(size);
}
void operator delete(void *p)
{
if (g_systemInitiated == false) free(p);
else
{
std::lock_guard<std::mutex> lock(g_mutex);
std::cout << "Inside delete() critical section" << std::endl;
// <-- Memory manager would be called here, dummy call to free() in stead
free(p);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
g_systemInitiated = true;
char *test = new char[100];
std::cout << "Allocated" << std::endl;
delete test;
std::cout << "Deleted" << std::endl;
return 0;
}
更新#6
向 Microsoft 提交了错误报告:https://connect.microsoft.com/VisualStudio/feedback/details/776596/std-mutex-not-a-constexpr-with-mtd-compiler-flag#details https://connect.microsoft.com/VisualStudio/feedback/details/776596/std-mutex-not-a-constexpr-with-mtd-compiler-flag#details