assert_only_one_thread.h
Go to the documentation of this file.
1 #ifndef cetlib_assert_only_one_thread_h
2 #define cetlib_assert_only_one_thread_h
3 
4 // ===================================================================
5 // CET_ASSERT_ONLY_ONE_THREAD()
6 //
7 // This macro is a utility that can be called wherever it is expected
8 // for only one thread to be accessing a particular block of code.
9 //
10 // It has similar semantics to the standard 'assert' macro:
11 //
12 // - It is disabled if NDEBUG is defined
13 // - If more than one thread is accessing that block of code at one
14 // time, std::abort is called.
15 // - It is encouraged to be used whenever single-threaded execution
16 // of a code block is a pre-condition.
17 //
18 // If the std::abort() is called, file, line-number, and function-name
19 // information will be provided.
20 // ===================================================================
21 
22 #include <atomic>
23 #include <iostream>
24 #include <mutex>
25 
26 namespace cet {
27  namespace detail {
28 
29  class ThreadCounter {
30  public:
31  explicit ThreadCounter(char const* filename,
32  unsigned const linenum,
33  char const* funcname)
34  : filename_{filename}, linenum_{linenum}, funcname_{funcname}
35  {}
36 
37  class Sentry; // Only the sentry can access the members
38 
39  private:
40  std::atomic<unsigned> counter_{0u};
42  unsigned const linenum_;
44  };
45 
47  public:
48  Sentry(ThreadCounter& tc, bool const terminate = true)
49  : tc_{tc}, terminate_{terminate}
50  {
51  if (++tc_.counter_ != 1u) {
52  // Do not guard the abort!
53  {
54  std::lock_guard<decltype(m_)> hold{m_};
55  std::cerr
56  << "Failed assert--more than one thread accessing location:\n"
57  << " " << tc_.filename_ << ':' << tc_.linenum_ << '\n'
58  << " function: " << tc_.funcname_ << '\n';
59  }
60  if (terminate_) {
61  std::abort();
62  }
63  }
64  }
65 
66  ~Sentry() noexcept { --tc_.counter_; }
67 
68  private:
70  bool const terminate_;
71  std::mutex m_{};
72  };
73  }
74 }
75 
76 #define CONCATENATE_HIDDEN(a, b) a##b
77 #define CONCATENATE(a, b) CONCATENATE_HIDDEN(a, b)
78 
79 #ifndef NDEBUG
80 #define CET_ASSERT_ONLY_ONE_THREAD() \
81  static cet::detail::ThreadCounter CONCATENATE(s, __LINE__){ \
82  __FILE__, __LINE__, __func__}; \
83  cet::detail::ThreadCounter::Sentry CONCATENATE(hold, __LINE__) \
84  { \
85  CONCATENATE(s, __LINE__) \
86  }
87 #else
88 #define CET_ASSERT_ONLY_ONE_THREAD() ((void)0)
89 #endif
90 
91 #endif /* cetlib_assert_only_one_thread_h */
92 
93 // Local variables:
94 // mode: c++
95 // End:
Sentry(ThreadCounter &tc, bool const terminate=true)
OStream cerr
Definition: OStream.cxx:7
string filename
Definition: shutoffs.py:106
ThreadCounter(char const *filename, unsigned const linenum, char const *funcname)
std::atomic< unsigned > counter_
enum BeamMode string