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 // vim: set sw=2 expandtab :
4 
5 // ===================================================================
6 // CET_ASSERT_ONLY_ONE_THREAD()
7 //
8 // This macro is a utility that can be called wherever it is expected
9 // for only one thread to be accessing a particular block of code.
10 //
11 // It has similar semantics to the standard 'assert' macro:
12 //
13 // - It is disabled if NDEBUG is defined
14 // - If more than one thread is accessing that block of code at one
15 // time, std::abort is called.
16 // - It is encouraged to be used whenever single-threaded execution
17 // of a code block is a pre-condition.
18 //
19 // If the std::abort() is called, file, line-number, and function-name
20 // information will be provided.
21 // ===================================================================
22 
23 #include <atomic>
24 #include <cstdlib>
25 #include <iostream>
26 #include <string>
27 
28 namespace cet::detail {
29 
30  class ThreadCounter {
31  public:
32  explicit ThreadCounter(char const* filename,
33  unsigned const linenum,
34  char const* funcname)
35  : filename_{filename}, linenum_{linenum}, funcname_{funcname}
36  {}
37 
38  class Sentry {
39  public:
40  ~Sentry() noexcept { --tc_.counter_; }
41  Sentry(ThreadCounter& tc, bool const terminate = true) : tc_{tc}
42  {
43  if (++tc_.counter_ == 1u) {
44  return;
45  }
46  std::cerr << "Failed assert--more than one thread accessing location:\n"
47  << " " << tc_.filename_ << ':' << tc_.linenum_ << '\n'
48  << " function: " << tc_.funcname_ << '\n';
49  if (terminate) {
50  std::abort();
51  }
52  }
53 
54  private:
56  };
57 
58  private:
60  unsigned const linenum_;
62  std::atomic<unsigned> counter_{0u};
63  };
64 
65 } // namespace cet::detail
66 
67 #ifdef NDEBUG
68 #define CET_ASSERT_ONLY_ONE_THREAD()
69 #else // NDEBUG
70 #define CET_ASSERT_ONLY_ONE_THREAD() \
71  static cet::detail::ThreadCounter s_tc_{__FILE__, __LINE__, __func__}; \
72  cet::detail::ThreadCounter::Sentry sentry_tc_ { s_tc_ }
73 #endif // NDEBUG
74 
75 #endif /* cetlib_assert_only_one_thread_h */
76 
77 // Local variables:
78 // mode: c++
79 // End:
Sentry(ThreadCounter &tc, bool const terminate=true)
std::string string
Definition: nybbler.cc:12
string filename
Definition: train.py:213
ThreadCounter(char const *filename, unsigned const linenum, char const *funcname)
std::atomic< unsigned > counter_