123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include "UserTypes.h"
- #include <AzCore/std/parallel/thread.h>
- #include <AzCore/std/parallel/containers/lock_free_queue.h>
- #include <AzCore/std/parallel/containers/lock_free_stamped_queue.h>
- #include <AzCore/std/functional.h>
- #include <AzCore/std/smart_ptr/shared_ptr.h>
- namespace UnitTest
- {
- using namespace AZStd;
- using namespace UnitTestInternal;
- class LockFreeQueue
- : public LeakDetectionFixture
- {
- protected:
- #ifdef _DEBUG
- static const int NUM_ITERATIONS = 5000;
- #else
- static const int NUM_ITERATIONS = 100000;
- #endif
- public:
- template <class Q>
- void Push(Q* queue)
- {
- for (int i = 0; i < NUM_ITERATIONS; ++i)
- {
- queue->push(i);
- }
- }
- template <class Q>
- void Pop(Q* queue)
- {
- int expected = 0;
- while (expected < NUM_ITERATIONS)
- {
- typename Q::value_type value = NUM_ITERATIONS;
- if (queue->pop(&value))
- {
- if (value == expected)
- {
- ++m_counter;
- }
- ++expected;
- }
- }
- }
- atomic<int> m_counter;
- };
- TEST_F(LockFreeQueue, LockFreeQueue)
- {
- lock_free_queue<int, MyLockFreeAllocator> queue;
- int result;
- AZ_TEST_ASSERT(queue.empty());
- AZ_TEST_ASSERT(!queue.pop(&result));
- queue.push(20);
- AZ_TEST_ASSERT(!queue.empty());
- AZ_TEST_ASSERT(queue.pop(&result));
- AZ_TEST_ASSERT(result == 20);
- AZ_TEST_ASSERT(queue.empty());
- AZ_TEST_ASSERT(!queue.pop(&result));
- queue.push(20);
- queue.push(30);
- AZ_TEST_ASSERT(!queue.empty());
- AZ_TEST_ASSERT(queue.pop(&result));
- AZ_TEST_ASSERT(result == 20);
- AZ_TEST_ASSERT(!queue.empty());
- AZ_TEST_ASSERT(queue.pop(&result));
- AZ_TEST_ASSERT(result == 30);
- AZ_TEST_ASSERT(queue.empty());
- AZ_TEST_ASSERT(!queue.pop(&result));
- {
- m_counter = 0;
- AZStd::thread thread0(AZStd::bind(&LockFreeQueue::Push<decltype(queue)>, this, &queue));
- AZStd::thread thread1(AZStd::bind(&LockFreeQueue::Pop<decltype(queue)>, this, &queue));
- thread0.join();
- thread1.join();
- AZ_TEST_ASSERT(m_counter == NUM_ITERATIONS);
- AZ_TEST_ASSERT(queue.empty());
- }
- }
- struct SharedInt {
- SharedInt() : m_ptr(nullptr) {}
- SharedInt(int i) : m_ptr(new int(i)) {}
- bool operator==(const SharedInt& other)
- {
- if (!m_ptr || !other.m_ptr)
- {
- return false;
- }
- return *m_ptr == *other.m_ptr;
- }
- private:
- AZStd::shared_ptr<int> m_ptr;
- };
- TEST_F(LockFreeQueue, LockFreeQueueNonTrivialDestructor)
- {
- lock_free_queue<SharedInt, MyLockFreeAllocator> queue;
- SharedInt result;
- AZ_TEST_ASSERT(queue.empty());
- AZ_TEST_ASSERT(!queue.pop(&result));
- queue.push(20);
- AZ_TEST_ASSERT(!queue.empty());
- AZ_TEST_ASSERT(queue.pop(&result));
- AZ_TEST_ASSERT(result == 20);
- AZ_TEST_ASSERT(queue.empty());
- AZ_TEST_ASSERT(!queue.pop(&result));
- queue.push(20);
- queue.push(30);
- AZ_TEST_ASSERT(!queue.empty());
- AZ_TEST_ASSERT(queue.pop(&result));
- AZ_TEST_ASSERT(result == 20);
- AZ_TEST_ASSERT(!queue.empty());
- AZ_TEST_ASSERT(queue.pop(&result));
- AZ_TEST_ASSERT(result == 30);
- AZ_TEST_ASSERT(queue.empty());
- AZ_TEST_ASSERT(!queue.pop(&result));
- {
- m_counter = 0;
- AZStd::thread thread0(AZStd::bind(&LockFreeQueue::Push<decltype(queue)>, this, &queue));
- AZStd::thread thread1(AZStd::bind(&LockFreeQueue::Pop<decltype(queue)>, this, &queue));
- thread0.join();
- thread1.join();
- AZ_TEST_ASSERT(m_counter == NUM_ITERATIONS);
- AZ_TEST_ASSERT(queue.empty());
- }
- }
- TEST_F(LockFreeQueue, LockFreeStampedQueue)
- {
- lock_free_stamped_queue<int, MyLockFreeAllocator> queue;
- int result;
- AZ_TEST_ASSERT(queue.empty());
- AZ_TEST_ASSERT(!queue.pop(&result));
- queue.push(20);
- AZ_TEST_ASSERT(!queue.empty());
- AZ_TEST_ASSERT(queue.pop(&result));
- AZ_TEST_ASSERT(result == 20);
- AZ_TEST_ASSERT(queue.empty());
- AZ_TEST_ASSERT(!queue.pop(&result));
- queue.push(20);
- queue.push(30);
- AZ_TEST_ASSERT(!queue.empty());
- AZ_TEST_ASSERT(queue.pop(&result));
- AZ_TEST_ASSERT(result == 20);
- AZ_TEST_ASSERT(!queue.empty());
- AZ_TEST_ASSERT(queue.pop(&result));
- AZ_TEST_ASSERT(result == 30);
- AZ_TEST_ASSERT(queue.empty());
- AZ_TEST_ASSERT(!queue.pop(&result));
- {
- m_counter = 0;
- AZStd::thread thread0(AZStd::bind(&LockFreeQueue::Push<decltype(queue)>, this, &queue));
- AZStd::thread thread1(AZStd::bind(&LockFreeQueue::Pop<decltype(queue)>, this, &queue));
- thread0.join();
- thread1.join();
- AZ_TEST_ASSERT(m_counter == NUM_ITERATIONS);
- AZ_TEST_ASSERT(queue.empty());
- }
- }
- TEST_F(LockFreeQueue, LockFreeStampedQueueNonTrivialDestructor)
- {
- lock_free_stamped_queue<SharedInt, MyLockFreeAllocator> queue;
- SharedInt result;
- AZ_TEST_ASSERT(queue.empty());
- AZ_TEST_ASSERT(!queue.pop(&result));
- queue.push(20);
- AZ_TEST_ASSERT(!queue.empty());
- AZ_TEST_ASSERT(queue.pop(&result));
- AZ_TEST_ASSERT(result == 20);
- AZ_TEST_ASSERT(queue.empty());
- AZ_TEST_ASSERT(!queue.pop(&result));
- queue.push(20);
- queue.push(30);
- AZ_TEST_ASSERT(!queue.empty());
- AZ_TEST_ASSERT(queue.pop(&result));
- AZ_TEST_ASSERT(result == 20);
- AZ_TEST_ASSERT(!queue.empty());
- AZ_TEST_ASSERT(queue.pop(&result));
- AZ_TEST_ASSERT(result == 30);
- AZ_TEST_ASSERT(queue.empty());
- AZ_TEST_ASSERT(!queue.pop(&result));
- {
- m_counter = 0;
- AZStd::thread thread0(AZStd::bind(&LockFreeQueue::Push<decltype(queue)>, this, &queue));
- AZStd::thread thread1(AZStd::bind(&LockFreeQueue::Pop<decltype(queue)>, this, &queue));
- thread0.join();
- thread1.join();
- AZ_TEST_ASSERT(m_counter == NUM_ITERATIONS);
- AZ_TEST_ASSERT(queue.empty());
- }
- }
- }
|