summaryrefslogtreecommitdiffstats
path: root/Tests/TestApp/src/SmartPointerTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Tests/TestApp/src/SmartPointerTest.cpp')
-rw-r--r--Tests/TestApp/src/SmartPointerTest.cpp746
1 files changed, 746 insertions, 0 deletions
diff --git a/Tests/TestApp/src/SmartPointerTest.cpp b/Tests/TestApp/src/SmartPointerTest.cpp
new file mode 100644
index 0000000..dbeed7f
--- /dev/null
+++ b/Tests/TestApp/src/SmartPointerTest.cpp
@@ -0,0 +1,746 @@
+/* Copyright 2015-2017 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+// EngineSandbox.cpp : Defines the entry point for the application.
+//
+
+#include "pch.h"
+#include <thread>
+#include "SmartPointerTest.h"
+#include "Errors.h"
+#include "DefaultRawMemoryAllocator.h"
+
+using namespace Diligent;
+
+template<typename Type>
+Type* MakeNewObj()
+{
+ return MakeNewRCObj<Type>().operator()();
+}
+
+void SmartPointerTest::CreateObject(Object **ppObj)
+{
+ *ppObj = MakeNewObj<Object>();
+ (*ppObj)->AddRef();
+}
+
+void SmartPointerTest::WaitForThreadStart(int VarId)
+{
+ std::unique_lock<std::mutex> lk(m_Mtx);
+ m_CondVar.wait(lk, [&]{return m_bThreadStart[VarId] || m_bStopThreads;});
+}
+
+void SmartPointerTest::StartThreadsAndWait(int VarId, size_t NumThreads)
+{
+ {
+ std::unique_lock<std::mutex> lk(m_Mtx);
+ m_bThreadStart[VarId] = true;
+ m_NumThreadsCompleted = 0;
+ }
+ m_CondVar.notify_all();
+
+ while((size_t)m_NumThreadsCompleted < NumThreads)
+ std::this_thread::yield();
+ m_bThreadStart[VarId] = false;
+ VERIFY_EXPR(m_NumThreadsCompleted == NumThreads);
+}
+
+void SmartPointerTest::WorkerThreadFunc(SmartPointerTest *This, size_t ThreadNum)
+{
+ while(!This->m_bStopThreads)
+ {
+ for(int i =0; i < NumThreadInterations; ++i)
+ {
+ // Wait until main() sends data
+ This->WaitForThreadStart(0);
+ if(This->m_bStopThreads)
+ {
+ This->m_NumThreadsCompleted++;
+ return;
+ }
+
+ {
+ auto *pObject = This->m_pSharedObject;
+ for(int j=0; j < 100; ++j)
+ {
+ //LOG_INFO_MESSAGE("t",std::this_thread::get_id(), ": AddRef" );
+ pObject->m_Value++;
+ pObject->AddRef();
+ }
+ This->m_NumThreadsCompleted++;
+
+ This->WaitForThreadStart(1);
+ for(int j=0; j < 100; ++j)
+ {
+ //LOG_INFO_MESSAGE("t",std::this_thread::get_id(), ": Release" );
+ pObject->m_Value--;
+ pObject->Release();
+ }
+ This->m_NumThreadsCompleted++;
+ }
+
+ {
+ This->WaitForThreadStart(0);
+ auto *pObject = This->m_pSharedObject;
+ auto *pRefCounters = pObject->GetReferenceCounters();
+ if (ThreadNum % 3 == 0)
+ {
+ pObject->m_Value++;
+ pObject->AddRef();
+ }
+ else
+ pRefCounters->AddWeakRef();
+ This->m_NumThreadsCompleted++;
+
+ This->WaitForThreadStart(1);
+ if (ThreadNum % 3 == 0)
+ {
+ pObject->m_Value--;
+ pObject->Release();
+ }
+ else
+ pRefCounters->ReleaseWeakRef();
+ This->m_NumThreadsCompleted++;
+ }
+
+ {
+ // Test interferences of ReleaseStrongRef() and GetObject()
+
+ // Goal: catch scenario when GetObject() runs between
+ // AtomicDecrement() and acquiring the lock in ReleaseStrongRef():
+
+ // m_lNumStrongReferences == 1
+ //
+
+ // Scenario I
+ //
+ // Thread 1 | Thread 2 | Thread 3
+ // | |
+ // | |
+ // | |
+ // | 1. Acquire the lock |
+ // | 2. Increment m_lNumStrongReferences |
+ // 1. Decrement m_lNumStrongReferences | 3. Read StrongRefCnt > 1 |
+ // 2. Test RefCount!=0 | 4. Return the reference to object |
+ // 3. DO NOT destroy the object | |
+ // 4. Wait for the lock | |
+
+
+ // Scenario I
+ //
+ // Thread 1 | Thread 2 | Thread 3
+ // | |
+ // | |
+ // 1. Decrement m_lNumStrongReferences | |
+ // | 1. Acquire the lock |
+ // 2. Test RefCount==0 | 2. Increment m_lNumStrongReferences |
+ // 3. Start destroying the object | 3. Read StrongRefCnt == 1 |
+ // 4. Wait for the lock | 4. DO NOT create the object |
+ // | 5. Decrement m_lNumStrongReferences |
+ // | | 1. Acquire the lock
+ // | | 2. Increment m_lNumStrongReferences
+ // | | 3. Read StrongRefCnt == 1
+ // | | 4. DO NOT create the object
+ // | | 5. Decrement m_lNumStrongReferences
+ // 5. Acquire the lock |
+ // 6. DESTROY the object |
+
+ This->WaitForThreadStart(0);
+ auto *pObject = This->m_pSharedObject;
+ RefCntWeakPtr<Object> weakPtr(pObject);
+ RefCntAutoPtr<Object> strongPtr, strongPtr2;
+ if (ThreadNum < 2)
+ {
+ strongPtr = pObject;
+ strongPtr->m_Value++;
+ }
+ else
+ weakPtr = WeakPtr(pObject);
+ This->m_NumThreadsCompleted++;
+
+ This->WaitForThreadStart(1);
+ if (ThreadNum == 0)
+ {
+ strongPtr->m_Value--;
+ strongPtr.Release();
+ }
+ else
+ {
+ strongPtr2 = weakPtr.Lock();
+ if(strongPtr2)
+ strongPtr2->m_Value++;
+ weakPtr.Release();
+ }
+ This->m_NumThreadsCompleted++;
+ }
+
+
+ {
+ This->WaitForThreadStart(0);
+ auto *pObject = This->m_pSharedObject;
+ RefCntWeakPtr<Object> weakPtr;
+ RefCntAutoPtr<Object> strongPtr;
+ if (ThreadNum % 4 == 0)
+ {
+ strongPtr = pObject;
+ strongPtr->m_Value++;
+ }
+ else
+ weakPtr = WeakPtr(pObject);
+ This->m_NumThreadsCompleted++;
+
+ This->WaitForThreadStart(1);
+ if (ThreadNum % 4 == 0)
+ {
+ strongPtr->m_Value--;
+ strongPtr.Release();
+ }
+ else
+ {
+ auto Ptr = weakPtr.Lock();
+ if(Ptr)
+ Ptr->m_Value++;
+ Ptr.Release();
+ }
+ This->m_NumThreadsCompleted++;
+ }
+ }
+ }
+}
+
+void SmartPointerTest::StartConcurrencyTest()
+{
+ auto numCores = std::thread::hardware_concurrency();
+ m_Threads.resize(numCores);
+ for(auto &t : m_Threads)
+ t = std::thread(WorkerThreadFunc, this, &t-m_Threads.data());
+}
+
+SmartPointerTest::~SmartPointerTest()
+{
+ m_bStopThreads = true;
+ StartThreadsAndWait(0, m_Threads.size());
+
+ for(auto &t : m_Threads)
+ t.join();
+
+ auto NumIterations = NumThreadInterations;
+ LOG_INFO_MESSAGE("SmartPointerTest: performed ", m_NumTestsPerformed, " concurrency tests with ", NumIterations, " iterations each");
+}
+
+void SmartPointerTest::RunConcurrencyTest()
+{
+ for(int i=0;i<NumThreadInterations; ++i)
+ {
+ m_pSharedObject = MakeNewObj<Object>();
+
+ StartThreadsAndWait(0, m_Threads.size());
+
+ StartThreadsAndWait(1, m_Threads.size());
+
+ m_pSharedObject = MakeNewObj<Object>();
+
+ StartThreadsAndWait(0, m_Threads.size());
+
+ StartThreadsAndWait(1, m_Threads.size());
+
+ m_pSharedObject = MakeNewObj<Object>();
+
+ StartThreadsAndWait(0, m_Threads.size());
+
+ StartThreadsAndWait(1, m_Threads.size());
+
+ m_pSharedObject = MakeNewObj<Object>();
+
+ StartThreadsAndWait(0, m_Threads.size());
+
+ StartThreadsAndWait(1, m_Threads.size());
+ }
+ ++m_NumTestsPerformed;
+}
+
+
+SmartPointerTest::SmartPointerTest() :
+ m_bThreadStart{false, false},
+ m_NumThreadsCompleted(0),
+ m_pSharedObject(nullptr)
+{
+ // Test constructors of RefCntAutoPtr
+ {
+ SmartPtr SP0;
+ SmartPtr SP1(nullptr);
+ auto *pRawPtr = MakeNewObj<Object>();
+ SmartPtr SP2(pRawPtr);
+ SmartPtr SP2_1(pRawPtr);
+
+ SmartPtr SP3(SP0);
+ SmartPtr SP4(SP2);
+ SmartPtr SP5(std::move(SP3));
+ SmartPtr SP6(std::move(SP4));
+ }
+
+ // Test Attach/Detach
+ {
+ {
+ SmartPtr SP0;
+ auto *pRawPtr = MakeNewObj<Object>();
+ SP0.Attach(nullptr);
+ SP0.Attach(pRawPtr);
+ pRawPtr->AddRef();
+ }
+
+ {
+ SmartPtr SP0;
+ auto *pRawPtr = MakeNewObj<Object>();
+ pRawPtr->AddRef();
+ SP0.Attach(pRawPtr);
+ SP0.Attach(nullptr);
+ }
+
+ {
+ SmartPtr SP0(MakeNewObj<Object>());
+ auto *pRawPtr = MakeNewObj<Object>();
+ SP0.Attach(pRawPtr);
+ pRawPtr->AddRef();
+ }
+
+ {
+ SmartPtr SP0(MakeNewObj<Object>());
+ auto *pRawPtr = MakeNewObj<Object>();
+ pRawPtr->AddRef();
+ SP0.Attach(pRawPtr);
+ auto *pRawPtr2 = SP0.Detach();
+ pRawPtr2->Release();
+
+ auto *pRawPtr3 = SmartPtr().Detach();
+ auto *pRawPtr4 = SmartPtr(MakeNewObj<Object>()).Detach();
+ pRawPtr4->Release();
+ }
+ }
+
+ // Test operator =
+ {
+ SmartPtr SP0;
+ auto pRawPtr1 = MakeNewObj<Object>();
+ SmartPtr SP1(pRawPtr1);
+ SmartPtr SP2(pRawPtr1);
+ SP0 = SP0;
+ SP0 = std::move(SP0);
+ SP0 = nullptr;
+ assert(SP0 == nullptr);
+
+ SP1 = pRawPtr1;
+ SP1 = SP1;
+ SP1 = std::move(SP1);
+ assert(SP1 == pRawPtr1);
+
+ SP1 = SP2;
+ SP1 = std::move(SP2);
+ assert(SP1 == pRawPtr1);
+
+ auto pRawPtr2 = MakeNewObj<Object>();
+ SmartPtr SP3(pRawPtr2);
+
+ SP0 = pRawPtr2;
+ SmartPtr SP4;
+ SP4 = SP3;
+ SmartPtr SP5;
+ SP5 = std::move(SP4);
+
+ SP1 = pRawPtr2;
+ SP1 = nullptr;
+ SP1 = std::move(SP5);
+ }
+
+ // Test logical operators
+ {
+ auto pRawPtr1 = MakeNewObj<Object>();
+ auto pRawPtr2 = MakeNewObj<Object>();
+ SmartPtr SP0, SP1(pRawPtr1), SP2(pRawPtr1), SP3(pRawPtr2);
+ assert( !SP0 );
+ bool b1 = SP0.operator bool();
+ assert( !b1 );
+ if(SP0)
+ assert( false );
+
+ assert( !(!SP1) );
+ assert( SP1 );
+ assert( SP0 != SP1 );
+ assert( SP0 == SP0 );
+ assert( SP1 == SP1 );
+ assert( SP1 == SP2 );
+ assert( SP1 != SP3 );
+ assert( SP0 < SP3 );
+ assert( (SP1 < SP3) == (pRawPtr1<pRawPtr2) );
+ }
+
+ // Test operator &
+ {
+ SmartPtr SP0, SP1(MakeNewObj<Object>()), SP2, SP3, SP4(MakeNewObj<Object>());
+ auto *pRawPtr = MakeNewObj<Object>();
+ pRawPtr->AddRef();
+
+ *static_cast<Object**>(&SP0) = pRawPtr;
+ SP0.Detach();
+ *&SP2 = pRawPtr;
+ SP2.Detach();
+
+ CreateObject(&SP3);
+
+ CreateObject(&SP1);
+ *static_cast<Object**>(&SP4) = pRawPtr;
+
+ {
+ SmartPtr SP5(MakeNewObj<Object>());
+ auto pDblPtr = &SP5;
+ *pDblPtr = MakeNewObj<Object>();
+ (*pDblPtr)->AddRef();
+ auto pDblPtr2 = &SP5;
+ CreateObject(pDblPtr2);
+ }
+
+ SmartPtr SP6(MakeNewObj<Object>());
+ // This will not work:
+ // Object **pDblPtr3 = &SP6;
+ // *pDblPtr3 = new Object;
+ }
+
+ // Test constructors of RefCntWeakPtr
+ {
+ SmartPtr SP0, SP1(MakeNewObj<Object>());
+ WeakPtr WP0;
+ WeakPtr WP1(WP0);
+ WeakPtr WP2(SP0);
+ WeakPtr WP3(SP1);
+ WeakPtr WP4(WP3);
+ WeakPtr WP5(std::move(WP0));
+ WeakPtr WP6(std::move(WP4));
+
+ auto *pRawPtr = MakeNewObj<Object>();
+ pRawPtr->AddRef();
+ WeakPtr WP7(pRawPtr);
+ pRawPtr->Release();
+ }
+
+ // Test operator =
+ {
+ auto *pRawPtr = MakeNewObj<Object>();
+ SmartPtr SP0, SP1(pRawPtr);
+ WeakPtr WP0, WP1(SP1), WP2(SP1);
+ WP0 = WP0;
+ WP0 = std::move(WP0);
+ WP1 = WP1;
+ WP1 = std::move(WP1);
+ WP1 = WP2;
+ WP1 = std::move(WP2);
+ WP1 = pRawPtr;
+ WP0 = pRawPtr;
+ WP0.Release();
+ WP0 = WP2;
+
+ WP1 = WP0;
+ WP0 = SP1;
+ WP2 = std::move(WP1);
+ }
+
+ // Test logical operators
+ {
+ SmartPtr SP0, SP1(MakeNewObj<Object>());
+ WeakPtr WP0, WP1(SP0), WP2(SP1), WP3(SP1);
+ assert( WP0 == WP1 );
+ assert( WP0 != WP2 );
+ assert( WP2 == WP3 );
+ SP1.Release();
+ assert( WP2 == WP3 );
+ }
+
+ // Test Lock()
+ {
+ SmartPtr SP0, SP1(MakeNewObj<Object>());
+ WeakPtr WP0, WP1(SP0), WP2(SP1);
+ WeakPtr WP3(WP2);
+ auto L1 = WP0.Lock();
+ assert( !L1 );
+ L1 = WP1.Lock();
+ assert( !L1 );
+ L1 = WP2.Lock();
+ assert( L1 );
+ L1 = WP3.Lock();
+ assert( L1 );
+ auto pRawPtr = SP1.Detach();
+ L1.Release();
+
+ L1 = WP3.Lock();
+ assert( L1 );
+ L1.Release();
+
+ pRawPtr->Release();
+
+ L1 = WP3.Lock();
+ assert( !L1 );
+ }
+
+ {
+ class OwnerTest : public RefCountedObject<IObject>
+ {
+ public:
+ OwnerTest(IReferenceCounters *pRefCounters) :
+ RefCountedObject<IObject>(pRefCounters),
+ Obj( NEW_RC_OBJ( DefaultRawMemoryAllocator::GetAllocator(), "Test object", Object, this)())
+ {
+ }
+
+ virtual void QueryInterface( const INTERFACE_ID &IID, IObject **ppInterface ){}
+ ~OwnerTest()
+ {
+ Obj->~Object();
+ DefaultRawMemoryAllocator::GetAllocator().Free(Obj);
+ }
+ private:
+ Object *Obj;
+ };
+
+ OwnerTest *pOwnerObject = MakeNewObj<OwnerTest>();
+ pOwnerObject->AddRef();
+ pOwnerObject->Release();
+ }
+
+ {
+ class SelfRefTest : public RefCountedObject<IObject>
+ {
+ public:
+ SelfRefTest(IReferenceCounters *pRefCounters) :
+ RefCountedObject<IObject>(pRefCounters),
+ wpSelf( this )
+ {}
+
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface ){}
+ private:
+ Diligent::RefCntWeakPtr<SelfRefTest> wpSelf;
+ };
+
+ SelfRefTest *pSelfRefTest = MakeNewObj<SelfRefTest>();
+ pSelfRefTest->AddRef();
+ pSelfRefTest->Release();
+ }
+
+ {
+ class ExceptionTest1 : public RefCountedObject<IObject>
+ {
+ public:
+ ExceptionTest1(IReferenceCounters *pRefCounters) :
+ RefCountedObject<IObject>(pRefCounters),
+ wpSelf(this)
+ {
+ throw std::runtime_error("test exception");
+ }
+
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface ){}
+ private:
+ Diligent::RefCntWeakPtr<ExceptionTest1> wpSelf;
+ };
+
+ try
+ {
+ auto *pExceptionTest = MakeNewObj<ExceptionTest1>();
+ }
+ catch(std::runtime_error &)
+ {
+
+ }
+ }
+
+ {
+ class ExceptionTest2 : public RefCountedObject<IObject>
+ {
+ public:
+ ExceptionTest2(IReferenceCounters *pRefCounters) :
+ RefCountedObject<IObject>(pRefCounters),
+ wpSelf(this)
+ {
+ throw std::runtime_error("test exception");
+ }
+
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface ){}
+ private:
+ Diligent::RefCntWeakPtr<ExceptionTest2> wpSelf;
+ };
+
+ try
+ {
+ auto *pExceptionTest = NEW_RC_OBJ( DefaultRawMemoryAllocator::GetAllocator(), "Test object", ExceptionTest2)();
+ }
+ catch(std::runtime_error &)
+ {
+
+ }
+ }
+
+ {
+ class ExceptionTest3 : public RefCountedObject<IObject>
+ {
+ public:
+ ExceptionTest3(IReferenceCounters *pRefCounters) :
+ RefCountedObject<IObject>(pRefCounters),
+ m_Member(*this)
+ {
+ }
+
+ class Subclass
+ {
+ public:
+ Subclass(ExceptionTest3 &parent) :
+ wpSelf(&parent)
+ {
+ throw std::runtime_error("test exception");
+ }
+ private:
+ Diligent::RefCntWeakPtr<ExceptionTest3> wpSelf;
+ };
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface ){}
+ private:
+ Subclass m_Member;
+ };
+
+ try
+ {
+ auto *pExceptionTest = NEW_RC_OBJ( DefaultRawMemoryAllocator::GetAllocator(), "Test object", ExceptionTest3)();
+ }
+ catch(std::runtime_error &)
+ {
+
+ }
+ }
+
+ {
+ class OwnerObject : public RefCountedObject<IObject>
+ {
+ public:
+ OwnerObject(IReferenceCounters *pRefCounters) :
+ RefCountedObject<IObject>(pRefCounters)
+ {}
+
+ void CreateMember()
+ {
+ try
+ {
+ m_pMember = NEW_RC_OBJ( DefaultRawMemoryAllocator::GetAllocator(), "Test object", ExceptionTest4, this)(*this);
+ }
+ catch (...)
+ {
+
+ }
+ }
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface ){}
+
+ class ExceptionTest4 : public RefCountedObject<IObject>
+ {
+ public:
+ ExceptionTest4(IReferenceCounters *pRefCounters, OwnerObject &owner) :
+ RefCountedObject<IObject>(pRefCounters),
+ m_Member(owner, *this)
+ {
+ }
+
+ class Subclass
+ {
+ public:
+ Subclass(OwnerObject &owner, ExceptionTest4 &parent) :
+ wpParent(&parent),
+ wpOwner(&owner)
+ {
+ throw std::runtime_error("test exception");
+ }
+ private:
+ Diligent::RefCntWeakPtr<ExceptionTest4> wpParent;
+ Diligent::RefCntWeakPtr<OwnerObject> wpOwner;
+ };
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface ){}
+ private:
+ Subclass m_Member;
+ };
+
+ RefCntAutoPtr<ExceptionTest4> m_pMember;
+ };
+
+ RefCntAutoPtr<OwnerObject> pOwner( NEW_RC_OBJ( DefaultRawMemoryAllocator::GetAllocator(), "Test object", OwnerObject)() );
+ pOwner->CreateMember();
+ }
+
+
+ {
+ class OwnerObject : public RefCountedObject<IObject>
+ {
+ public:
+ OwnerObject(IReferenceCounters *pRefCounters) :
+ RefCountedObject<IObject>(pRefCounters)
+ {
+ m_pMember = NEW_RC_OBJ( DefaultRawMemoryAllocator::GetAllocator(), "Test object", ExceptionTest4, this)(*this);
+ }
+
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface ){}
+
+ class ExceptionTest4 : public RefCountedObject<IObject>
+ {
+ public:
+ ExceptionTest4(IReferenceCounters *pRefCounters, OwnerObject &owner) :
+ RefCountedObject<IObject>(pRefCounters),
+ m_Member(owner, *this)
+ {
+ }
+
+ class Subclass
+ {
+ public:
+ Subclass(OwnerObject &owner, ExceptionTest4 &parent) :
+ wpParent(&parent),
+ wpOwner(&owner)
+ {
+ throw std::runtime_error("test exception");
+ }
+ private:
+ Diligent::RefCntWeakPtr<ExceptionTest4> wpParent;
+ Diligent::RefCntWeakPtr<OwnerObject> wpOwner;
+ };
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface ){}
+ private:
+ Subclass m_Member;
+ };
+
+ RefCntAutoPtr<ExceptionTest4> m_pMember;
+ };
+
+ try
+ {
+ RefCntAutoPtr<OwnerObject> pOwner( NEW_RC_OBJ( DefaultRawMemoryAllocator::GetAllocator(), "Test object", OwnerObject)() );
+ }
+ catch (...)
+ {
+
+ }
+ }
+
+ StartConcurrencyTest();
+ RunConcurrencyTest();
+}
+