Простое утверждение для упорядоченного не повторного вызова?
-
28-10-2019 - |
Вопрос
У меня две функции:
void prepare () и void finish (), которые будут называться последовательно похожими на:
prepare();
<do something>;
finish();
...
prepare();
<do something>;
finish();
Я хочу сделать простое утверждение, чтобы просто проверить, что их на самом деле называют таким образом, и что их не называют одновременно или вне порядка в приложении.
Это приложение представляет собой однопоточное приложение. Это простая проверка здравомыслия разработки/тестирования, чтобы убедиться, что эти функции называются в порядке, и что по какой-либо причине их не называют одновременно. Кроме того, эти утверждения/проверки здравомыслия должны быть опущены из производственного кода, поскольку производительность имеет решающее значение!
Будет ли простой Assert (), как эта работа лучше всего?
int test = 0;
void prepare() {
assert(++test == 1);
.
.
.
}
void finish() {
assert(--test == 0);
.
.
.
}
Решение
Ваш код в порядке, если вам не нужно разрешить гнездовать prepare
а также finish
вызовы
Если гнездование не разрешено, вы можете использовать bool
вместо int
:
bool locked = false;;
void prepare() {
assert( ! locked );
locked = true;
...
}
void finish() {
assert( locked );
locked = false;
...
}
Другие советы
Вы можете захотеть изменить
int test = 0;
к
#ifndef NDEBUG
int test = 0;
#endif
Чтобы удовлетворить ваше требование, что «любой код, относящийся к этому тесту, должен быть опущен из производства».
Вы, наверное, хотите:
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
}
Здесь есть условие гонки: два одновременных случая prepare
может взять ценность test
В то же время, тогда оба увеличивают его в регистр, чтобы получить 1
, затем сделайте сравнение, чтобы получить true
.
Делая это volatile
является не помогу. Анкет Вместо этого вы должны надеть мутекс на test
, вот так:
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);
}
Если вы положите <do something>;
в а class
Вы можете сократить потребность в чеке вообще:
Просто попросите конструктора prepare
И звонок деструктора finish
. Анкет Затем автоматически применяется, что их называют соответствующим образом.
Обратите внимание, что все еще применяются проблемы с параллелизмом и гнездованием: если вы хотите предотвратить гнездо Счетчик должен быть защищен мутекс.
Также обратите внимание, что вы также можете сделать личный operator new/delete
Чтобы кто -то не создавал его на куче и не разрушал его.
Поскольку вы используете C ++, почему бы не использовать RAII? Вам все равно нужно проверить использование повторного входа, но Raii значительно упрощает вещи. В сочетании с Larsmans 'Mutex а также Устранение Raedwald's в 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()
}
Внутренний пример, вы просто не может Сделайте что -нибудь без приготовления, и окончание всегда будет происходить, даже если исключение будет брошено.
Примечание о ndebug: если вы используете его таким образом, убедитесь, что оно всегда определено или всегда не определен в все Переводные единицы, в отличие от того, как он используется для ASSERT (позволяя определить и не определен в различных точках).