5 c++ multithreading mutex c++11 visual-studio-2012
我们有一个内部存储器管理器,我们使用其中一个产品.内存管理器会覆盖new
和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
...
}
Run Code Online (Sandbox Code Playgroud)
导致线程在旋转中永远挂起:
#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;
...
}
Run Code Online (Sandbox Code Playgroud)
更新#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;
...
}
Run Code Online (Sandbox Code Playgroud)
更新#3
乔纳森威克利建议我应该尝试unique_lock
和/或lock_guard
,但锁仍然在旋转.
unique_lock
测试:
#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;
...
}
Run Code Online (Sandbox Code Playgroud)
lock_guard
测试:
#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;
...
}
Run Code Online (Sandbox Code Playgroud)
我认为我的问题是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);
...
}
}
Run Code Online (Sandbox Code Playgroud)
这导致死锁情况,我看不到任何好的解决方案除了使我自己的锁定不会产生任何调用new
或delete
锁定或解锁时.
更新#4
我已经实现了我自己的自定义递归互斥锁,它没有调用,new
或者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;
...
}
Run Code Online (Sandbox Code Playgroud)
更新#5
尝试了Jonathan Wakely的建议,并发现微软实施C++ 11 Mutexs似乎有些不对劲; 如果使用/MTd
(多线程调试)编译器标志编译,他的示例会挂起,但如果使用/MDd
(多线程调试DLL)编译器标志编译,则可以正常工作.正如Jonathan正确指出的那样,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;
}
Run Code Online (Sandbox Code Playgroud)
更新#6
向Microsoft提交了一个错误报告:https: //connect.microsoft.com/VisualStudio/feedback/details/776596/std-mutex-not-a-constexpr-with-mtd-compiler-flag#details
互斥体库使用new
, std::mutex 默认情况下不是递归的(即可重入的)。一个先有鸡还是先有蛋的问题。
更新正如下面的评论所指出的,使用 std::recursive_mutex 可能有效。但是,经典的 C++ 全局变量静态初始化顺序定义不明确的问题依然存在,外部访问全局互斥锁的危险也依然存在(最好将其放在匿名命名空间中。)
更新2您可能太早将g_systemInitiated 切换为true,即在互斥体有机会完成其初始化之前,因此“首次通过”调用永远不会发生malloc()
。要强制执行此操作,您可以尝试通过调用分配器模块中的初始化函数来替换 main() 中的分配:
namespace {
std::recursive_mutex g_mutex;
bool g_initialized = false;
}
void initialize()
{
g_mutex.lock();
g_initialized = true;
g_mutex.unlock();
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2328 次 |
最近记录: |