Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

LinkedList.hpp

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file LinkedList.hpp
00003     Lock-free sorted linked list.
00004  */
00005 //----------------------------------------------------------------------------
00006 
00007 #ifndef LINKEDLIST_HPP
00008 #define LINKEDLIST_HPP
00009 
00010 #include "Benzene.hpp"
00011 #include "SafeBool.hpp"
00012 #include <cassert>
00013 #include <iostream>
00014 #include <boost/utility.hpp>
00015 
00016 _BEGIN_BENZENE_NAMESPACE_
00017 
00018 //----------------------------------------------------------------------------
00019 
00020 /** A node occuring in an instance of LinkedList. */
00021 template<typename T>
00022 class ListNode
00023 {
00024 public:
00025     ListNode();
00026 
00027     ListNode(const T& data);
00028 
00029     bool AddChild(ListNode<T>* child, ListNode<T>* successor) volatile;
00030 
00031     void Delete() volatile;
00032 
00033 private:
00034     T m_data;
00035 
00036     bool m_locked;
00037 
00038     bool m_deleted;
00039 
00040     ListNode<T>* m_next;
00041 
00042     ListNode<T>* m_dead;
00043 
00044     struct ScopedLock
00045     {
00046         volatile ListNode<T>& m_obj;
00047 
00048         ScopedLock(volatile ListNode<T>& obj) 
00049             : m_obj(obj)
00050         { 
00051             while (!__sync_bool_compare_and_swap(&m_obj.m_locked, false, true))
00052                 ;
00053         }
00054         ~ScopedLock()
00055         {
00056             m_obj.m_locked = false;
00057         }
00058     };
00059 
00060     ListNode<T>* GetNext() volatile;
00061 
00062     void TryFixLink(ListNode<T>* node) volatile;
00063 
00064     template<typename U> friend class Pool;
00065     
00066     template<typename U> friend class ListIterator;
00067 
00068     template<typename U> friend class LinkedList;
00069 };
00070 
00071 
00072 template<typename T>
00073 ListNode<T>::ListNode()
00074     : m_locked(false),
00075       m_deleted(false),
00076       m_next(0),
00077       m_dead(0)
00078 {
00079 }
00080 
00081 template<typename T>
00082 ListNode<T>::ListNode(const T& data)
00083     : m_data(data),
00084       m_locked(false),
00085       m_deleted(false),
00086       m_next(0),
00087       m_dead(0)
00088 {
00089 }
00090 
00091 /** Locks the node and adds the given child. */
00092 template<typename T>
00093 bool ListNode<T>::AddChild(ListNode<T>* child, ListNode<T>* successor) volatile
00094 {
00095     ScopedLock lock(*this);
00096     if (!m_deleted && m_next == successor)
00097     {
00098         child->m_next = m_next;
00099         m_next = child;
00100         return true;
00101     }
00102     return false;
00103 }
00104 
00105 /** Logically deletes this node. 
00106     Node must be locked while doing so to prevent the node from being
00107     deleted inside another thread's AddChild() call. */
00108 template<typename T>
00109 void ListNode<T>::Delete() volatile
00110 {
00111     ScopedLock lock(*this);
00112     m_deleted = true;
00113 }
00114 
00115 /** Attempts to physically delete a logically deleted node. */
00116 template<typename T>
00117 void ListNode<T>::TryFixLink(ListNode<T>* node) volatile
00118 {
00119     ScopedLock lock(*this);
00120     if (m_next == node)
00121         m_next = node->m_next;
00122 }
00123 
00124 /** Returns the next node in the list. 
00125     Tries to physically delete any logically deleted nodes it
00126     encounters along the way. */
00127 template<typename T>
00128 ListNode<T>* ListNode<T>::GetNext() volatile
00129 {
00130     ListNode<T>* node = m_next;
00131     while ((node != 0) && node->m_deleted)
00132     {
00133         TryFixLink(node);
00134         node = node->m_next;
00135     }
00136     return node;
00137 }
00138 
00139 //----------------------------------------------------------------------------
00140 
00141 /** Pool of pre-allocated memory. 
00142     Allocates more memory when current amount is used up.
00143 */
00144 template<typename T>
00145 class Pool : boost::noncopyable
00146 {
00147 public:
00148 
00149     static const std::size_t CHUNK_SIZE = 1 << 24; // 16MB
00150 
00151     Pool();
00152 
00153     ~Pool();
00154 
00155     std::size_t Allocated() const;
00156 
00157     std::size_t ChunkSize() const;
00158 
00159     /** Grabs memory from pool in threadsafe manner. */
00160     ListNode<T>* Get() volatile;
00161 
00162     /** Adds a node to the list of dead nodes in a threadsafe manner. */
00163     void AddToDeadList(ListNode<T>* node) volatile;
00164 
00165     /** Puts node back on pool, not threadsafe. */
00166     void Put(ListNode<T>* node);
00167 
00168     /** Returns dead nodes to pool. */
00169     void RaiseTheDead();
00170 
00171 private:
00172     ListNode<T>* m_head;
00173     
00174     ListNode<T>* m_dead;
00175 
00176     bool m_lockedHead;
00177 
00178     bool m_lockedDead;
00179 
00180     std::size_t m_allocated;
00181 
00182     std::size_t m_chunkSize;
00183 
00184     std::vector<ListNode<T>* > m_chunks;
00185 
00186     void Allocate();
00187 };
00188 
00189 template<typename T>
00190 Pool<T>::Pool()
00191     : m_head(0),
00192       m_dead(0),
00193       m_lockedHead(false),
00194       m_lockedDead(false),
00195       m_allocated(0),
00196       m_chunkSize(CHUNK_SIZE)
00197 {
00198     Allocate();
00199 }
00200 
00201 template<typename T>
00202 Pool<T>::~Pool()
00203 {
00204     for (std::size_t i = 0; i < m_chunks.size(); ++i)
00205         delete [] m_chunks[i];
00206 }
00207 
00208 template<typename T>
00209 std::size_t Pool<T>::Allocated() const
00210 {
00211     return m_allocated;
00212 }
00213 
00214 template<typename T>
00215 std::size_t Pool<T>::ChunkSize() const
00216 {
00217     return m_chunkSize;
00218 }
00219 
00220 template<typename T>
00221 void Pool<T>::Allocate()
00222 {
00223     assert(m_head == 0);
00224     std::size_t num = m_chunkSize / sizeof(ListNode<T>);
00225     ListNode<T>* data = new ListNode<T>[num];
00226     m_chunks.push_back(data);
00227     for (std::size_t i = 0; i < num - 1; ++i)
00228         data[i].m_next = &data[i + 1];
00229     data[num - 1].m_next = 0;
00230     m_head = data;
00231     m_allocated += num * sizeof(ListNode<T>);
00232 }
00233 
00234 template<typename T>
00235 ListNode<T>* Pool<T>::Get() volatile
00236 {
00237     while (!__sync_bool_compare_and_swap(&m_lockedHead, false, true));
00238     if (m_head == 0)
00239     {
00240         // Strip volatile-ness since we are locked
00241         Pool<T>& ref = const_cast<Pool<T>&>(*this);
00242         ref.Allocate();
00243     }
00244     ListNode<T>* ret = m_head;
00245     m_head = m_head->m_next;
00246     m_lockedHead = false;
00247     return ret;
00248 }
00249 
00250 template<typename T>
00251 void Pool<T>::AddToDeadList(ListNode<T>* node) volatile
00252 {
00253     while (!__sync_bool_compare_and_swap(&m_lockedDead, false, true));
00254     node->m_dead = m_dead;
00255     m_dead = node;
00256     m_lockedDead = false;
00257 }
00258 
00259 template<typename T>
00260 void Pool<T>::RaiseTheDead()
00261 {
00262     ListNode<T>* node = m_dead;
00263     while (node)
00264     {
00265         ListNode<T>* next = node->m_dead;
00266         node->m_dead = 0;
00267         Put(node);
00268         node = next;
00269     }
00270     m_dead = 0;
00271 }
00272 
00273 template<typename T>
00274 void Pool<T>::Put(ListNode<T>* node)
00275 {
00276     node->m_next = m_head;
00277     m_head = node;
00278 }
00279 
00280 //----------------------------------------------------------------------------
00281 
00282 /** Lock-free linked list. 
00283     Uses memory from the supplied Pool object. 
00284 */
00285 template<typename T>
00286 class LinkedList
00287 {
00288 public:
00289     LinkedList(Pool<T>& pool);
00290 
00291     LinkedList(const LinkedList<T>& other);
00292 
00293     virtual ~LinkedList();
00294 
00295     bool Empty() const;
00296 
00297     void Add(const T& data);
00298 
00299     void Remove(const T& data);
00300     
00301     void Clear();
00302 
00303     void operator=(const LinkedList<T>& other);
00304 
00305     bool operator==(const LinkedList<T>& other) const;
00306 
00307 private:
00308     template <typename U> friend class ListIterator;
00309 
00310     Pool<T>& m_pool;
00311 
00312     mutable ListNode<T> m_head;
00313 
00314     void CopyList(const LinkedList<T>& other);
00315 };
00316 
00317 template<typename T>
00318 LinkedList<T>::LinkedList(Pool<T>& pool)
00319     : m_pool(pool)
00320 {
00321     m_head.m_next = 0;
00322 }
00323 
00324 template<typename T>
00325 LinkedList<T>::LinkedList(const LinkedList<T>& other)
00326     : m_pool(other.m_pool)
00327 {
00328     CopyList(other);
00329 }
00330 
00331 template<typename T>
00332 LinkedList<T>::~LinkedList()
00333 {
00334 }
00335 
00336 template<typename T>
00337 bool LinkedList<T>::Empty() const
00338 {
00339     return m_head.GetNext() == 0;
00340 }
00341 
00342 template<typename T>
00343 void LinkedList<T>::Clear()
00344 {
00345     ListNode<T>* node = m_head.GetNext();
00346     while (node != 0)
00347     {
00348         ListNode<T>* next = node.GetNext();
00349         m_pool.Put(node);
00350         node = next;
00351     }
00352     m_head.m_next = 0;
00353 }
00354 
00355 template<typename T>
00356 void LinkedList<T>::CopyList(const LinkedList<T>& other)
00357 {
00358     assert(m_head.m_next == 0);
00359     ListNode<T>* them = other.m_head.GetNext();
00360     ListNode<T>* mine = m_head;
00361     while (them != 0)
00362     {
00363         ListNode<T>* child = new (m_pool.Get()) ListNode<T>(them->m_data);
00364         mine->AddChild(child);
00365         mine = mine->GetNext();
00366         them = them->GetNext();
00367     }
00368 }
00369 
00370 template<typename T>
00371 void LinkedList<T>::Add(const T& data)
00372 {
00373     ListNode<T>* node = 0;
00374     while (true)
00375     {
00376         ListNode<T>* current = &m_head;
00377         ListNode<T>* next = current->GetNext();
00378         while ((next != 0) && next->m_data < data)
00379         {
00380             current = next;
00381             next = current->GetNext();
00382         }
00383         // At this point: (next == 0 || next->m_data >= data)
00384 
00385         // Check for duplicate
00386         if ((next != 0) && next->m_data == data)
00387             break;
00388 
00389         // Try to add it in this location
00390         if (node == 0)
00391             node = new (m_pool.Get()) ListNode<T>(data);
00392         if (current->AddChild(node, next))
00393             break;
00394     }
00395 }
00396 
00397 template<typename T>
00398 void LinkedList<T>::Remove(const T& data)
00399 {
00400     ListNode<T>* parent = &m_head;
00401     ListNode<T>* next = parent->GetNext();
00402     while ((next != 0) && next->m_data != data)
00403     {
00404         parent = next;
00405         next = parent->GetNext();
00406     }
00407     if (next != 0) 
00408     {
00409         next->Delete();
00410         parent->TryFixLink(next);
00411         m_pool.AddToDeadList(next);
00412     }
00413 }
00414 
00415 template<typename T>
00416 void LinkedList<T>::operator=(const LinkedList<T>& other)
00417 {
00418     Clear();
00419     CopyList(other);
00420 }
00421 
00422 template<typename T>
00423 bool LinkedList<T>::operator==(const LinkedList<T>& other) const
00424 {
00425     ListNode<T>* mine = m_head.GetNext();
00426     ListNode<T>* them = other.m_head.GetNext();
00427     while ((mine != 0) && (them != 0))
00428     {
00429         if (mine->m_data != them->m_data)
00430             return false;
00431         mine = mine->GetNext();
00432         them = them->GetNext();
00433     }
00434     return (mine != 0) == (them != 0);
00435 }
00436 
00437 //----------------------------------------------------------------------------
00438 
00439 /** Iterates over an instance of LinkedList. */
00440 template<typename T>
00441 class ListIterator : public SafeBool<ListIterator<T> >
00442 {
00443 public:
00444     ListIterator(LinkedList<T>& lst);
00445 
00446     T& operator*();
00447 
00448     ListIterator<T>& operator++();
00449     
00450     bool boolean_test() const;
00451 
00452 private:
00453     ListNode<T>* m_current;
00454 
00455     template <typename U> friend class LinkedList;
00456 };
00457 
00458 template<typename T>
00459 ListIterator<T>::ListIterator(LinkedList<T>& lst)
00460     : m_current(lst.m_head.GetNext())
00461 {
00462 }
00463 
00464 template<typename T>
00465 T& ListIterator<T>::operator*()
00466 {
00467     return m_current->m_data;
00468 }
00469 
00470 template<typename T>
00471 ListIterator<T>& ListIterator<T>::operator++()
00472 {
00473     m_current = m_current->GetNext();
00474     return *this;
00475 }
00476 
00477 template<typename T>
00478 bool ListIterator<T>::boolean_test() const
00479 {
00480     return m_current != 0;
00481 }
00482 
00483 //----------------------------------------------------------------------------
00484 
00485 _END_BENZENE_NAMESPACE_
00486 
00487 #endif // LINKEDLIST_HPP


6 Jan 2011 Doxygen 1.6.3