BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
threadsafestack.h
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // qt-mvvm: Model-view-view-model framework for large GUI applications
4 //
5 //! @file mvvm/model/mvvm/utils/threadsafestack.h
6 //! @brief Defines class CLASS?
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2020
11 //! @authors Gennady Pospelov et al, Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
15 #ifndef BORNAGAIN_MVVM_MODEL_MVVM_UTILS_THREADSAFESTACK_H
16 #define BORNAGAIN_MVVM_MODEL_MVVM_UTILS_THREADSAFESTACK_H
17 
18 #include "mvvm/model_export.h"
19 #include <atomic>
20 #include <condition_variable>
21 #include <memory>
22 #include <mutex>
23 #include <stack>
24 #include <stdexcept>
25 #include <thread>
26 
27 //! @file mvvm/model/mvvm/utils/threadsafestack.h
28 //! @brief Thread-safe stack borrowed from Anthony Williams, C++ Concurrency in Action, Second
29 //! edition.
30 
31 namespace ModelView {
32 
33 struct empty_stack : public std::exception {
34  const char* what() const noexcept { return "Empty stack"; }
35 };
36 
37 //! @class threadsafe_stack
38 //! @brief Thread-safe stack borrowed from Anthony Williams, C++ Concurrency in Action, Second
39 //! edition.
40 
41 template <typename T> class threadsafe_stack {
42 private:
43  std::stack<T> data;
44  mutable std::mutex m;
45  std::condition_variable data_condition;
46  std::atomic<bool> in_waiting_state{true};
47 
48 public:
52  {
53  std::lock_guard<std::mutex> lock(m);
54  data = other.data;
55  }
56  threadsafe_stack& operator=(const threadsafe_stack& other) = delete;
57 
58  void push(T new_value)
59  {
60  std::lock_guard<std::mutex> lock(m);
61  data.push(std::move(new_value));
62  data_condition.notify_one();
63  }
64 
65  //! Updates top value in a stack.
66 
67  void update_top(T new_value)
68  {
69  std::lock_guard<std::mutex> lock(m);
70  if (!data.empty())
71  data.pop();
72  data.push(std::move(new_value));
73  data_condition.notify_one();
74  }
75 
76  void wait_and_pop(T& value)
77  {
78  std::unique_lock<std::mutex> lock(m);
79  data_condition.wait(lock, [this] { return !data.empty() || !in_waiting_state; });
80  if (data.empty())
81  throw empty_stack();
82  value = std::move(data.top());
83  data.pop();
84  }
85 
86  std::shared_ptr<T> wait_and_pop()
87  {
88  std::unique_lock<std::mutex> lock(m);
89  data_condition.wait(lock, [this] { return !data.empty() || !in_waiting_state; });
90  if (data.empty())
91  throw empty_stack();
92  std::shared_ptr<T> const res(std::make_shared<T>(std::move(data.top())));
93  data.pop();
94  return res;
95  }
96 
97  bool try_pop(T& value)
98  {
99  std::lock_guard<std::mutex> lock(m);
100  if (data.empty())
101  return false;
102  value = std::move(data.top());
103  data.pop();
104  return true;
105  }
106 
107  std::shared_ptr<T> try_pop()
108  {
109  std::lock_guard<std::mutex> lock(m);
110  if (data.empty())
111  return std::shared_ptr<T>();
112  std::shared_ptr<T> res(std::make_shared<T>(std::move(data.top())));
113  data.pop();
114  return res;
115  }
116 
117  bool empty() const
118  {
119  std::lock_guard<std::mutex> lock(m);
120  return data.empty();
121  }
122 
123  //! Terminates waiting in wait_and_pop methods.
124 
125  void stop()
126  {
127  std::lock_guard<std::mutex> lock(m);
128  in_waiting_state = false;
129  data_condition.notify_all();
130  }
131 };
132 
133 } // namespace ModelView
134 
135 #endif // BORNAGAIN_MVVM_MODEL_MVVM_UTILS_THREADSAFESTACK_H
Thread-safe stack borrowed from Anthony Williams, C++ Concurrency in Action, Second edition.
std::atomic< bool > in_waiting_state
void update_top(T new_value)
Updates top value in a stack.
void stop()
Terminates waiting in wait_and_pop methods.
std::shared_ptr< T > wait_and_pop()
std::condition_variable data_condition
std::shared_ptr< T > try_pop()
threadsafe_stack & operator=(const threadsafe_stack &other)=delete
threadsafe_stack(const threadsafe_stack &other)
materialitems.h Collection of materials to populate MaterialModel.
const char * what() const noexcept