mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Refactor Stoppable:
The Stoppable interface aids in the enforcement of invariants needed to successful start and stop a multi-threaded application composed of classes that depend on each other in complex ways. * Test written to confirm the current behavior. * Comments updated to reflect the current behavior. * Public API reduced to what is currently in use. * Protected data members made private. * volatile bool members changed to std::atomic<bool>. * std::atomic<int> members changed to std::atomic<bool>. * Name storage uses std::string
This commit is contained in:
committed by
Vinnie Falco
parent
68fe1a7c8f
commit
eb64a4387d
445
beast/threads/impl/Stoppable.test.cpp
Normal file
445
beast/threads/impl/Stoppable.test.cpp
Normal file
@@ -0,0 +1,445 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <beast/threads/Stoppable.h>
|
||||
|
||||
namespace beast {
|
||||
|
||||
class Stoppable_test
|
||||
: public unit_test::suite
|
||||
{
|
||||
/*
|
||||
R
|
||||
/ | \
|
||||
/ | \
|
||||
A B C
|
||||
/ | \ /\ |
|
||||
D E F G H I
|
||||
|
|
||||
J
|
||||
*/
|
||||
unsigned count = 0;
|
||||
|
||||
class D
|
||||
: public Stoppable
|
||||
{
|
||||
Stoppable_test& test_;
|
||||
public:
|
||||
D(Stoppable& parent, Stoppable_test& test)
|
||||
: Stoppable("D", parent)
|
||||
, test_(test)
|
||||
{}
|
||||
|
||||
void onPrepare() override
|
||||
{
|
||||
test_.expect(++test_.count == 9, "D::onPrepare called out of order");
|
||||
}
|
||||
|
||||
void onStart() override
|
||||
{
|
||||
test_.expect(--test_.count == 0, "D::onStart called out of order");
|
||||
}
|
||||
|
||||
void onStop() override
|
||||
{
|
||||
test_.expect(++test_.count == 11, "D::onStop called out of order");
|
||||
}
|
||||
|
||||
void onChildrenStopped() override
|
||||
{
|
||||
Stoppable::stopped();
|
||||
test_.expect(--test_.count == 2, "D::onChildrenStopped called out of order");
|
||||
}
|
||||
};
|
||||
|
||||
class J
|
||||
: public Stoppable
|
||||
{
|
||||
Stoppable_test& test_;
|
||||
public:
|
||||
J(Stoppable& parent, Stoppable_test& test)
|
||||
: Stoppable("J", parent)
|
||||
, test_(test)
|
||||
{}
|
||||
|
||||
void onPrepare() override
|
||||
{
|
||||
test_.expect(++test_.count == 7, "J::onPrepare called out of order");
|
||||
}
|
||||
|
||||
void onStart() override
|
||||
{
|
||||
test_.expect(--test_.count == 1, "J::onStart called out of order");
|
||||
}
|
||||
|
||||
void onStop() override
|
||||
{
|
||||
test_.expect(++test_.count == 10, "J::onStop called out of order");
|
||||
}
|
||||
|
||||
void onChildrenStopped() override
|
||||
{
|
||||
Stoppable::stopped();
|
||||
test_.expect(--test_.count == 4, "J::onChildrenStopped called out of order");
|
||||
}
|
||||
};
|
||||
|
||||
class E
|
||||
: public Stoppable
|
||||
{
|
||||
J j_;
|
||||
Stoppable_test& test_;
|
||||
public:
|
||||
E(Stoppable& parent, Stoppable_test& test)
|
||||
: Stoppable("E", parent)
|
||||
, j_(*this, test)
|
||||
, test_(test)
|
||||
{}
|
||||
|
||||
void onPrepare() override
|
||||
{
|
||||
test_.expect(++test_.count == 8, "E::onPrepare called out of order");
|
||||
}
|
||||
|
||||
void onStart() override
|
||||
{
|
||||
test_.expect(--test_.count == 2, "E::onStart called out of order");
|
||||
}
|
||||
|
||||
void onStop() override
|
||||
{
|
||||
test_.expect(++test_.count == 9, "E::onStop called out of order");
|
||||
}
|
||||
|
||||
void onChildrenStopped() override
|
||||
{
|
||||
Stoppable::stopped();
|
||||
test_.expect(--test_.count == 3, "E::onChildrenStopped called out of order");
|
||||
}
|
||||
};
|
||||
|
||||
class F
|
||||
: public Stoppable
|
||||
{
|
||||
Stoppable_test& test_;
|
||||
public:
|
||||
F(Stoppable& parent, Stoppable_test& test)
|
||||
: Stoppable("F", parent)
|
||||
, test_(test)
|
||||
{}
|
||||
|
||||
void onPrepare() override
|
||||
{
|
||||
test_.expect(++test_.count == 6, "F::onPrepare called out of order");
|
||||
}
|
||||
|
||||
void onStart() override
|
||||
{
|
||||
test_.expect(--test_.count == 3, "F::onStart called out of order");
|
||||
}
|
||||
|
||||
void onStop() override
|
||||
{
|
||||
test_.expect(++test_.count == 8, "F::onStop called out of order");
|
||||
}
|
||||
|
||||
void onChildrenStopped() override
|
||||
{
|
||||
Stoppable::stopped();
|
||||
test_.expect(--test_.count == 5, "F::onChildrenStopped called out of order");
|
||||
}
|
||||
};
|
||||
|
||||
class A
|
||||
: public Stoppable
|
||||
{
|
||||
enum {running, please_stop, have_stopped};
|
||||
D d_;
|
||||
E e_;
|
||||
F f_;
|
||||
Stoppable_test& test_;
|
||||
std::atomic<int> stop_;
|
||||
public:
|
||||
A(Stoppable& parent, Stoppable_test& test)
|
||||
: Stoppable("A", parent)
|
||||
, d_(*this, test)
|
||||
, e_(*this, test)
|
||||
, f_(*this, test)
|
||||
, test_(test)
|
||||
, stop_(running)
|
||||
{}
|
||||
|
||||
void run()
|
||||
{
|
||||
while (stop_ == running)
|
||||
;
|
||||
stop_ = have_stopped;
|
||||
}
|
||||
|
||||
void onPrepare() override
|
||||
{
|
||||
test_.expect(++test_.count == 10, "A::onPrepare called out of order");
|
||||
}
|
||||
|
||||
void onStart() override
|
||||
{
|
||||
test_.expect(--test_.count == 4, "A::onStart called out of order");
|
||||
}
|
||||
|
||||
void onStop() override
|
||||
{
|
||||
test_.expect(++test_.count == 7, "A::onStop called out of order");
|
||||
}
|
||||
|
||||
void onChildrenStopped() override
|
||||
{
|
||||
stop_ = please_stop;
|
||||
while (stop_ != have_stopped)
|
||||
;
|
||||
Stoppable::stopped();
|
||||
test_.expect(--test_.count == 1, "A::onChildrenStopped called out of order");
|
||||
}
|
||||
};
|
||||
|
||||
class G
|
||||
: public Stoppable
|
||||
{
|
||||
Stoppable_test& test_;
|
||||
public:
|
||||
G(Stoppable& parent, Stoppable_test& test)
|
||||
: Stoppable("G", parent)
|
||||
, test_(test)
|
||||
{}
|
||||
|
||||
void onPrepare() override
|
||||
{
|
||||
test_.expect(++test_.count == 4, "G::onPrepare called out of order");
|
||||
}
|
||||
|
||||
void onStart() override
|
||||
{
|
||||
test_.expect(--test_.count == 5, "G::onStart called out of order");
|
||||
}
|
||||
|
||||
void onStop() override
|
||||
{
|
||||
test_.expect(++test_.count == 6, "G::onStop called out of order");
|
||||
}
|
||||
|
||||
void onChildrenStopped() override
|
||||
{
|
||||
Stoppable::stopped();
|
||||
test_.expect(--test_.count == 7, "G::onChildrenStopped called out of order");
|
||||
}
|
||||
};
|
||||
|
||||
class H
|
||||
: public Stoppable
|
||||
{
|
||||
Stoppable_test& test_;
|
||||
public:
|
||||
H(Stoppable& parent, Stoppable_test& test)
|
||||
: Stoppable("H", parent)
|
||||
, test_(test)
|
||||
{}
|
||||
|
||||
void onPrepare() override
|
||||
{
|
||||
test_.expect(++test_.count == 3, "H::onPrepare called out of order");
|
||||
}
|
||||
|
||||
void onStart() override
|
||||
{
|
||||
test_.expect(--test_.count == 6, "H::onStart called out of order");
|
||||
}
|
||||
|
||||
void onStop() override
|
||||
{
|
||||
test_.expect(++test_.count == 5, "H::onStop called out of order");
|
||||
}
|
||||
|
||||
void onChildrenStopped() override
|
||||
{
|
||||
Stoppable::stopped();
|
||||
test_.expect(--test_.count == 8, "H::onChildrenStopped called out of order");
|
||||
}
|
||||
};
|
||||
|
||||
class B
|
||||
: public Stoppable
|
||||
{
|
||||
G g_;
|
||||
H h_;
|
||||
Stoppable_test& test_;
|
||||
public:
|
||||
B(Stoppable& parent, Stoppable_test& test)
|
||||
: Stoppable("B", parent)
|
||||
, g_(*this, test)
|
||||
, h_(*this, test)
|
||||
, test_(test)
|
||||
{}
|
||||
|
||||
void onPrepare() override
|
||||
{
|
||||
test_.expect(++test_.count == 5, "B::onPrepare called out of order");
|
||||
}
|
||||
|
||||
void onStart() override
|
||||
{
|
||||
test_.expect(--test_.count == 7, "B::onStart called out of order");
|
||||
}
|
||||
|
||||
void onStop() override
|
||||
{
|
||||
test_.expect(++test_.count == 4, "B::onStop called out of order");
|
||||
}
|
||||
|
||||
void onChildrenStopped() override
|
||||
{
|
||||
Stoppable::stopped();
|
||||
test_.expect(--test_.count == 6, "B::onChildrenStopped called out of order");
|
||||
}
|
||||
};
|
||||
|
||||
class I
|
||||
: public Stoppable
|
||||
{
|
||||
Stoppable_test& test_;
|
||||
public:
|
||||
I(Stoppable& parent, Stoppable_test& test)
|
||||
: Stoppable("I", parent)
|
||||
, test_(test)
|
||||
{}
|
||||
|
||||
void onPrepare() override
|
||||
{
|
||||
test_.expect(++test_.count == 1, "I::onPrepare called out of order");
|
||||
}
|
||||
|
||||
void onStart() override
|
||||
{
|
||||
test_.expect(--test_.count == 8, "I::onStart called out of order");
|
||||
}
|
||||
|
||||
void onStop() override
|
||||
{
|
||||
test_.expect(++test_.count == 3, "I::onStop called out of order");
|
||||
}
|
||||
|
||||
void onChildrenStopped() override
|
||||
{
|
||||
Stoppable::stopped();
|
||||
test_.expect(--test_.count == 10, "I::onChildrenStopped called out of order");
|
||||
}
|
||||
};
|
||||
|
||||
class C
|
||||
: public Stoppable
|
||||
{
|
||||
I i_;
|
||||
Stoppable_test& test_;
|
||||
public:
|
||||
C(Stoppable& parent, Stoppable_test& test)
|
||||
: Stoppable("C", parent)
|
||||
, i_(*this, test)
|
||||
, test_(test)
|
||||
{}
|
||||
|
||||
void onPrepare() override
|
||||
{
|
||||
test_.expect(++test_.count == 2, "C::onPrepare called out of order");
|
||||
}
|
||||
|
||||
void onStart() override
|
||||
{
|
||||
test_.expect(--test_.count == 9, "C::onStart called out of order");
|
||||
}
|
||||
|
||||
void onStop() override
|
||||
{
|
||||
test_.expect(++test_.count == 2, "C::onStop called out of order");
|
||||
}
|
||||
|
||||
void onChildrenStopped() override
|
||||
{
|
||||
Stoppable::stopped();
|
||||
test_.expect(--test_.count == 9, "C::onChildrenStopped called out of order");
|
||||
}
|
||||
};
|
||||
|
||||
class Root
|
||||
: public RootStoppable
|
||||
{
|
||||
std::thread a_;
|
||||
B b_;
|
||||
C c_;
|
||||
Stoppable_test& test_;
|
||||
public:
|
||||
Root(Stoppable_test& test)
|
||||
: RootStoppable("R")
|
||||
, a_(&A::run, std::make_unique<A>(*this, test))
|
||||
, b_(*this, test)
|
||||
, c_(*this, test)
|
||||
, test_(test)
|
||||
{}
|
||||
|
||||
void run()
|
||||
{
|
||||
prepare();
|
||||
start();
|
||||
stop();
|
||||
}
|
||||
|
||||
void onPrepare() override
|
||||
{
|
||||
test_.expect(++test_.count == 11, "Root::onPrepare called out of order");
|
||||
}
|
||||
|
||||
void onStart() override
|
||||
{
|
||||
test_.expect(--test_.count == 10, "Root::onStart called out of order");
|
||||
}
|
||||
|
||||
void onStop() override
|
||||
{
|
||||
test_.expect(++test_.count == 1, "Root::onStop called out of order");
|
||||
}
|
||||
|
||||
void onChildrenStopped() override
|
||||
{
|
||||
a_.join();
|
||||
Stoppable::stopped();
|
||||
test_.expect(--test_.count == 0, "Root::onChildrenStopped called out of order");
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
void run()
|
||||
{
|
||||
{
|
||||
Root rt(*this);
|
||||
rt.run();
|
||||
}
|
||||
pass();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(Stoppable,beast_core,beast);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user