| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- /* Copyright The kNet Project.
- 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
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License. */
- #pragma once
- /** @file LockFreePoolAllocator.h
- @brief The PoolAllocatable<T> and LockFreePoolAllocator<T> template classes. */
- #include <iostream>
- #include "Atomics.h"
- namespace kNet
- {
- template<typename T>
- struct PoolAllocatable
- {
- /// Points to the next item in the lock-free linked list. Do not access or
- /// dereference this variable in client code, as it is used internally by
- /// LockFreePoolAllocator only.
- T * volatile next;
- };
- /// T must implement PoolAllocatable.
- template<typename T>
- class LockFreePoolAllocator
- {
- public:
- LockFreePoolAllocator()
- :root(0)
- {
- }
- ~LockFreePoolAllocator()
- {
- UnsafeClearAll();
- }
- /// Allocates a new object of type T. Call Free() to deallocate the object.
- T *New()
- {
- // Currently the use of lockfree allocation pool is disabled, since it has a known race condition, documented below.
- return new T();
- /*
- for(;;)
- {
- T *allocated = root;
- if (!allocated) // If the root is null, there are no objects in the pool, so we must create new from the runtime heap.
- {
- allocated = new T();
- allocated->next = 0;
- return allocated;
- }
- ///\bug Note that this function is not thread-safe. Accessing allocated->next may already be dangling if another thread has deleted it.
- T *newRoot = allocated->next;
- if (CmpXChgPointer((void**)&root, newRoot, allocated))
- {
- allocated->next = 0;
- return allocated;
- }
- }
- */
- }
- void Free(T *ptr)
- {
- delete ptr;
- // Currently the use of lockfree allocation pool is disabled, since it has a known race condition.
- /*
- if (!ptr)
- return;
- assert(ptr != root);
- for(;;)
- {
- ptr->next = root;
- if (CmpXChgPointer((void**)&root, ptr, ptr->next))
- return;
- }
- */
- }
- /// Deallocates all cached unused nodes in this pool. Thread-safe and lock-free. If you are manually tearing
- /// down the pool and there are no other threads accessing this, you may call the even faster version
- /// UnsafeClearAll(), which ignores compare-and-swap updates.
- void ClearAll()
- {
- while(root)
- {
- T *node = New();
- delete node;
- }
- }
- /// A fast method to free all items allocated in the pool.
- /// Not thread-safe, only call when you can guarantee there are no threads calling New() or Free().
- void UnsafeClearAll()
- {
- assert(!DebugHasCycle());
- T *node = root;
- while(node)
- {
- T *next = node->next;
- delete node;
- node = next;
- }
- root = 0;
- }
- /// A debugging function that checks whether the underlying linked list has a cycle or not. Not thread-safe!
- bool DebugHasCycle()
- {
- T *n1 = root;
- if (!n1)
- return false;
- T *n2 = n1->next;
- while(n2 != 0)
- {
- if (n1 == n2)
- return true;
- n1 = n1->next;
- n2 = n2->next;
- if (n2)
- n2 = n2->next;
- }
- return false;
- }
- /// A debugging function that prints out all the objects in the pool. Not thread-safe!
- void DumpPool()
- {
- using namespace std;
- T *node = root;
- cout << "Root: 0x" << ios::hex << root << ".Next: " << ios::hex << (root ? root->next : 0) << std::endl;
- int size = 0;
- if (node)
- node = node->next;
- while(node)
- {
- cout << "Node: 0x" << ios::hex << node << ".Next: " << ios::hex << (node ? node->next : 0) << std::endl;
- node = node->next;
- ++size;
- }
- cout << "Total: " << size << " elements." << endl;
- }
- private:
- T * volatile root;
- };
- } // ~kNet
|