A simple statement for an ordered call without re-entry?

I have two functions:

void prepare () and void finish (), which will be called sequentially:

prepare(); <do something>; finish(); ... prepare(); <do something>; finish(); 

I want to make a simple statement to simply verify that they are actually called in this way and that they are not calling at the same time or out of order in the application.

This application is a single-threaded application. This is a simple health check / health check to make sure that these functions are called in order and for some reason they are not called at the same time. In addition, these statements / sanity checks should be excluded from production code, as performance is critical!

it will be easier to state () how is this work best?

 int test = 0; void prepare() { assert(++test == 1); . . . } void finish() { assert(--test == 0); . . . } 
+4
source share
6 answers

Your code is fine, unless you need to allow nested calls to prepare and finish .

If nesting is not allowed, you can use bool instead of int :

 bool locked = false;; void prepare() { assert( ! locked ); locked = true; ... } void finish() { assert( locked ); locked = false; ... } 
+1
source

There is a race condition: two parallel prepare instances can simultaneously take the value test , then both increase it in the register so that both get 1 , then do a comparison to get true .

To do << 24> will not help . Instead, you should put the mutexes on test , for example:

 boost::mutex mtx; int test = 0; void prepare() { boost::mutex::scoped_try_lock lock(&mtx); assert(lock.owns_lock()); assert(test++ == 0); // ... } void finish() { boost::mutex::scoped_try_lock lock(&mtx); assert(lock.owns_lock()); assert(--test == 0); } 
+3
source

You might want to change

 int test = 0; 

to

 #ifndef NDEBUG int test = 0; #endif 

to satisfy your requirements that "any code related to this test should be left out of production."

+3
source

you probably want:

 int test = 0; void prepare() { // enter critical section assert(test++ == 0); . . . // leave critical section } void finish() { // enter critical section assert(--test == 0); . . . // leave critical section } 
+3
source

Since you are using C ++, why not use RAII? You will still need to verify the use of re-participation, but RAII will greatly simplify the situation. Combined with the larsmans mutex and the Raedwald exception in NDEBUG :

 struct Frobber { Frobber() { assert(mtx.try_lock()); #ifndef NDEBUG try { // in case prepare throws #endif prepare(); #ifndef NDEBUG } catch (...) { mtx.unlock(); throw; } #endif } void something(); // And the other actions that can be performed between preparation and finishing. ~Frobber() { finish(); #ifndef NDEBUG mtx.unlock(); #endif } private: #ifndef NDEBUG static boost::mutex mtx; #endif Frobber(Frobber const&); // not defined; 0x: = delete Frobber& operator=(Frobber const&); // not defined; 0x: = delete }; #ifndef NDEBUG boost::mutex Frobber::mtx; #endif void example() { Frobber blah; // instead of prepare() blah.something(); // implicit finish() } 

Inside the example, you simply cannot do something without preliminary preparation, and completion will always occur, even if an exception is thrown.

Side note about NDEBUG: if you use it this way, make sure it is either always defined or always undefined in all translation units, as opposed to how it is used for approval (allowing you to define it and undefined at different points).

+1
source

If you put <do something>; in class , you can reduce the need for validation in general:

Just call the prepare constructor and call the finish destructor. Then it automatically forcibly determines that they are called accordingly.

Note that concurrency and nesting problems still apply: if you want to prevent nesting, you still need some kind of global state (static member of the class?) To keep track of this, and if it is used in more than one access flow to This counter must be protected by a mutex.

Also note that you can also do a private operator new/delete so that someone doesn't create it on the heap and destroy it.

+1
source

Source: https://habr.com/ru/post/1337969/


All Articles