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:
33 
35 
37 
38  template <typename... Args>
39  T* makeAndHold(Args&&... args);
40 
41  private:
42 
43  class Node {
44  public:
45 
46  template <typename... Args>
47  Node(Node* iNext, Args&&... args);
48  Node const* next() const { return next_; }
49  void setNext(Node* v) { next_ = v; }
50  T* address() { return &data_; }
51 
52  private:
53 
54  Node* next_;
56  };
57 
58  std::atomic<Node*> front_;
59  };
60 
61  template <typename T>
63  front_(nullptr) {
64  }
65 
66  template <typename T>
68  Node const* node = front_.load();
69  while (node) {
70  Node const* next = node->next();
71  delete node;
72  node = next;
73  }
74  }
75 
76  template <typename T>
77  template <typename... Args>
79  Node* expected = front_.load();
80  Node* newNode = new Node(expected, std::forward<Args>(args)...);
81  while (!front_.compare_exchange_strong(expected, newNode)) {
82  // another thread changed front_ before us so try again
83  newNode->setNext(expected);
84  }
85  return newNode->address();
86  }
87 
88  template <typename T>
89  template <typename... Args>
91  next_(iNext),
92  data_(std::forward<Args>(args)...) {
93  }
94 }
95 
96 #endif
#define nullptr
HLT enums.
long double T