CMS 3D CMS Logo

ThreadSafeAddOnlyContainer.h
Go to the documentation of this file.
1 #ifndef FWCore_Concurrency_ThreadSafeAddOnlyContainer_h
2 #define FWCore_Concurrency_ThreadSafeAddOnlyContainer_h
3 
4 #include <atomic>
5 #include <utility>
6 
7 // This container will make objects and hold them. The container deletes
8 // the objects when the container is destroyed and only then. The client
9 // of the container should not delete them. The client must save the pointers
10 // to the objects that are returned by the makeAndHold function. There
11 // is no other way to access them. The pointers remain valid for as long
12 // as the container still exists.
13 
14 // It is safe for multiple threads to concurrently call makeAndHold.
15 
16 // Warning, none of the memory used by this is deallocated before the
17 // entire container is destroyed. If used in the wrong way, this container
18 // could cause memory hoarding.
19 
20 // The original use case for this was that we had complex large objects
21 // in thread local storage and this was causing problems. Instead we
22 // we stored the complex objects in this container and used one thread
23 // local pointer to save the pointer to the object corresponding to
24 // to each thread. Instead of storing a complex object in thread local
25 // storage we were able to only store a simple pointer. There may be
26 // other uses for this.
27 
28 namespace edm {
29 
30  template <typename T>
32  public:
34 
36 
37  template <typename... Args>
38  T* makeAndHold(Args&&... args);
39 
40  private:
41  class Node {
42  public:
43  template <typename... Args>
44  Node(Node* iNext, Args&&... args);
45  Node const* next() const { return next_; }
46  void setNext(Node* v) { next_ = v; }
47  T* address() { return &data_; }
48 
49  private:
50  Node* next_;
52  };
53 
54  std::atomic<Node*> front_;
55  };
56 
57  template <typename T>
59 
60  template <typename T>
62  Node const* node = front_.load();
63  while (node) {
64  Node const* next = node->next();
65  delete node;
66  node = next;
67  }
68  }
69 
70  template <typename T>
71  template <typename... Args>
73  Node* expected = front_.load();
74  Node* newNode = new Node(expected, std::forward<Args>(args)...);
75  while (!front_.compare_exchange_strong(expected, newNode)) {
76  // another thread changed front_ before us so try again
77  newNode->setNext(expected);
78  }
79  return newNode->address();
80  }
81 
82  template <typename T>
83  template <typename... Args>
85  : next_(iNext), data_(std::forward<Args>(args)...) {}
86 } // namespace edm
87 
88 #endif
TGeoNode Node
#define nullptr
HLT enums.
long double T