当社の製品で使用する内部メモリマネージャがあります。メモリマネージャは、new
とdelete
演算子をオーバーライドし、シングルスレッドアプリケーションで正常に動作します。しかし、私は今もマルチスレッドアプリケーションでも動作させることを任されています。私の理解では、次の擬似コードはうまくいくはずですが、それはtry_lock()
でさえスピンします。何か案は?新しい演算子をオーバーライドするとstd :: mutexロックがハングします
更新#1
原因 "アクセス違反":
#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::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::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
ジョナサンWakelyは、私が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;
...
}
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;
...
}
私は私の問題は、施錠時に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
または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;
...
}
更新#5
ジョナサンWakelyの提案を試みたが、間違いなくC++ 11のミューテックスのMicrosoftの実装に問題があると思われることがわかりました。彼の例は、/MTd
(マルチスレッドデバッグ)コンパイラフラグでコンパイルされた場合にハングしますが、/MDd
(マルチスレッドデバッグDLL)コンパイラフラグでコンパイルすると正常に動作します。ジョナサンが正しく指摘したようにstd::mutex
の実装はconstexpr
であるはずです。
#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
:ここで私は実装の問題をテストするために使用VS 2012 C++のコードである https://connect.microsoft.com/VisualStudio/feedback/details/776596/std-mutex-not-a-constexpr-with-mtd-compiler-flag#details
を私はどこにあなたのg_mutexを定義するか、それがリンクすることができますどのように表示されないのですか? 2つの宣言がある、あなたはそのうちの1つの前にexternを持つべきです。 –
新しい演算子と削除演算子は実際に何をしますか(メモリの割り当て/解放を除いて)? –
@claptrap擬似コードです。 –