File test/lib/dynamo/README.md changed (mode: 100644) (index 64a5f8e..d9f92fc) |
1 |
|
## dynamo
|
|
2 |
|
|
|
3 |
|
### Objective:
|
|
4 |
|
|
|
5 |
|
Dispatch work to agents.
|
|
6 |
|
|
|
7 |
|
### Interface:
|
|
8 |
|
```
|
|
9 |
|
namespace om636 {
|
|
10 |
|
namespace control {
|
|
11 |
|
|
|
12 |
|
template <typename... T>
|
|
13 |
|
class Batch {
|
|
14 |
|
public:
|
|
15 |
|
typedef std::function<void(T...)> function_type;
|
|
16 |
|
typedef std::shared_ptr<function_type> agent_type;
|
|
17 |
|
typedef agent_type listener_type;
|
|
18 |
|
|
|
19 |
|
virtual ~Batch() = default;
|
|
20 |
|
virtual agent_type hook(function_type) = 0;
|
|
21 |
|
virtual agent_type hook_once(function_type) = 0;
|
|
22 |
|
virtual void invoke(T...) = 0;
|
|
23 |
|
};
|
|
24 |
|
|
|
25 |
|
} // control
|
|
26 |
|
} // om636
|
|
27 |
|
```
|
|
28 |
|
|
|
29 |
|
### Dependencies
|
|
30 |
|
|
|
31 |
|
Dynamo uses Circuit for thread syncronization
|
|
32 |
|
|
|
33 |
|
### Plan
|
|
34 |
|
|
|
35 |
|
Instead of copy and insert elements inside of invok, push the elements one by one as they get traversed (obviosly don't add elements that are dead)...
|
|
36 |
|
|
|
37 |
|
![doc header](https://s3-us-west-2.amazonaws.com/mod-resources/mod-header.svg)
|
|
|
1 |
|
# dynamo |
|
2 |
|
|
|
3 |
|
Dispatch work to agents. |
|
4 |
|
|
|
5 |
|
## Interface |
|
6 |
|
``` |
|
7 |
|
#pragma once |
|
8 |
|
|
|
9 |
|
#include <functional> |
|
10 |
|
#include <memory> |
|
11 |
|
|
|
12 |
|
namespace om636 { |
|
13 |
|
namespace control { |
|
14 |
|
|
|
15 |
|
template <typename... T> |
|
16 |
|
class Batch { |
|
17 |
|
public: |
|
18 |
|
typedef std::function<void(T...)> function_type; |
|
19 |
|
typedef std::shared_ptr<function_type> agent_type; |
|
20 |
|
typedef agent_type listener_type; |
|
21 |
|
|
|
22 |
|
virtual ~Batch() = default; |
|
23 |
|
virtual agent_type hook(function_type) = 0; |
|
24 |
|
virtual agent_type hook_once(function_type) = 0; |
|
25 |
|
virtual void invoke(T...) = 0; |
|
26 |
|
}; |
|
27 |
|
|
|
28 |
|
} // control |
|
29 |
|
} // om636 |
|
30 |
|
|
|
31 |
|
``` |
|
32 |
|
|
|
33 |
|
|
|
34 |
|
## Example |
|
35 |
|
``` |
|
36 |
|
#include <tmp/src/test.h> |
|
37 |
|
|
|
38 |
|
#include <lib/dynamo/src/factory.h> |
|
39 |
|
#include <lib/dynamo/src/interface.h> |
|
40 |
|
|
|
41 |
|
int main() |
|
42 |
|
{ |
|
43 |
|
auto b = om636::control::make_batch<int>(); |
|
44 |
|
|
|
45 |
|
int sum { 0 }; |
|
46 |
|
|
|
47 |
|
auto q = b->hook([&](int i) { sum += i; }); |
|
48 |
|
auto p = b->hook([&](int i) { sum *= i; }); |
|
49 |
|
b->invoke(5); |
|
50 |
|
return sum == 25; |
|
51 |
|
} |
|
52 |
|
``` |
|
53 |
|
|
|
54 |
|
### Dependencies |
|
55 |
|
|
|
56 |
|
Dynamo uses Circuit for thread syncronization |
|
57 |
|
|
|
58 |
|
### Plan |
|
59 |
|
|
|
60 |
|
Instead of copy and insert elements inside of invok, push the elements one by one as they get traversed (obviosly don't add elements that are dead)... |
|
61 |
|
|
|
62 |
|
![doc header](https://s3-us-west-2.amazonaws.com/mod-resources/mod-header.svg) |
File test/lib/dynamo/src/impl/batch.h changed (mode: 100644) (index ca98a2f..a7c8267) |
4 |
4 |
#include <memory> |
#include <memory> |
5 |
5 |
#include <vector> |
#include <vector> |
6 |
6 |
|
|
7 |
|
#include <lib/circuit/src/index.h> |
|
|
7 |
|
#include <lib/circuit/src/impl/circuit_host.h> |
8 |
8 |
|
|
9 |
9 |
#include "../interface.h" |
#include "../interface.h" |
10 |
10 |
|
|
11 |
11 |
namespace om636 { |
namespace om636 { |
12 |
12 |
namespace control { |
namespace control { |
13 |
|
template <typename... T> |
|
|
13 |
|
|
|
14 |
|
template <template <typename> typename P, typename... T> |
14 |
15 |
class BatchImpl : public Batch<T...> { |
class BatchImpl : public Batch<T...> { |
15 |
16 |
public: |
public: |
16 |
17 |
typedef Batch<T...> base_type; |
typedef Batch<T...> base_type; |
|
... |
... |
namespace control { |
23 |
24 |
void invoke(T...) override; |
void invoke(T...) override; |
24 |
25 |
|
|
25 |
26 |
typedef std::weak_ptr<typename agent_type::element_type> pointer_type; |
typedef std::weak_ptr<typename agent_type::element_type> pointer_type; |
26 |
|
typedef std::tuple<pointer_type, bool> tuple_type; |
|
27 |
|
typedef circuit::CircuitQueue<tuple_type> batch_type; |
|
28 |
|
batch_type& elements(); |
|
29 |
|
const batch_type& elements() const; |
|
|
27 |
|
typedef std::tuple<pointer_type, bool> tuple_type; |
|
28 |
|
typedef circuit::CircuitHost<tuple_type, P> batch_type; |
|
29 |
|
batch_type& impl_ref(); |
|
30 |
|
const batch_type& impl_ref() const; |
30 |
31 |
|
|
31 |
32 |
private: |
private: |
32 |
33 |
template <typename U> |
template <typename U> |
33 |
34 |
void invoke(U, T...); |
void invoke(U, T...); |
34 |
35 |
|
|
35 |
|
batch_type m_elements; |
|
|
36 |
|
batch_type m_impl; |
36 |
37 |
}; |
}; |
37 |
38 |
|
|
38 |
39 |
} //control |
} //control |
File test/lib/dynamo/src/impl/batch.hxx changed (mode: 100644) (index 3bac54b..013aa65) |
1 |
1 |
namespace om636 { |
namespace om636 { |
2 |
2 |
namespace control { |
namespace control { |
3 |
3 |
///////////////////////////////////////////////////////////////////////////////////// |
///////////////////////////////////////////////////////////////////////////////////// |
4 |
|
template <typename... T> |
|
5 |
|
auto BatchImpl<T...>::hook(function_type callback) -> agent_type |
|
|
4 |
|
template <template <typename> typename P, typename... T> |
|
5 |
|
auto BatchImpl<P, T...>::hook(function_type callback) -> agent_type |
6 |
6 |
{ |
{ |
7 |
|
auto agent(std::make_shared<function_type>(callback)); |
|
8 |
|
m_elements.push(std::make_tuple<pointer_type, bool>(agent, true)); |
|
|
7 |
|
using namespace std; |
|
8 |
|
auto agent(make_shared<function_type>(callback)); |
|
9 |
|
impl_ref().push(make_tuple<pointer_type, bool>(agent, true)); |
9 |
10 |
return agent; |
return agent; |
10 |
11 |
} |
} |
11 |
12 |
|
|
12 |
13 |
///////////////////////////////////////////////////////////////////////////////////// |
///////////////////////////////////////////////////////////////////////////////////// |
13 |
|
template <typename... T> |
|
14 |
|
auto BatchImpl<T...>::hook_once(function_type callback) -> agent_type |
|
|
14 |
|
template <template <typename> typename P, typename... T> |
|
15 |
|
auto BatchImpl<P, T...>::hook_once(function_type callback) -> agent_type |
15 |
16 |
{ |
{ |
16 |
|
auto agent(std::make_shared<function_type>(callback)); |
|
17 |
|
m_elements.push(std::make_tuple<pointer_type, bool>(agent, false)); |
|
|
17 |
|
using namespace std; |
|
18 |
|
auto agent(make_shared<function_type>(callback)); |
|
19 |
|
impl_ref().push(make_tuple<pointer_type, bool>(agent, false)); |
18 |
20 |
return agent; |
return agent; |
19 |
21 |
} |
} |
20 |
22 |
|
|
21 |
23 |
///////////////////////////////////////////////////////////////////////////////////// |
///////////////////////////////////////////////////////////////////////////////////// |
22 |
|
template <typename... T> |
|
23 |
|
void BatchImpl<T...>::invoke(T... arg) |
|
|
24 |
|
template <template <typename> typename P, typename... T> |
|
25 |
|
void BatchImpl<P, T...>::invoke(T... arg) |
24 |
26 |
{ |
{ |
|
27 |
|
using namespace std; |
25 |
28 |
batch_type traverse; |
batch_type traverse; |
26 |
|
traverse.swap(elements()); |
|
|
29 |
|
traverse.swap(impl_ref()); |
27 |
30 |
tuple_type agent; |
tuple_type agent; |
28 |
31 |
while (traverse.check_pop(agent)) { |
while (traverse.check_pop(agent)) { |
29 |
|
agent_type s(std::get<0>(agent).lock()); |
|
|
32 |
|
agent_type s(get<0>(agent).lock()); |
30 |
33 |
if (s) { |
if (s) { |
31 |
34 |
(*s)(arg...); |
(*s)(arg...); |
32 |
|
} |
|
33 |
|
s = std::get<0>(agent).lock(); |
|
34 |
|
if (s && std::get<1>(agent)) { |
|
35 |
|
elements().push(std::move(agent)); |
|
|
35 |
|
} |
|
36 |
|
s = get<0>(agent).lock(); |
|
37 |
|
if (s && get<1>(agent)) { |
|
38 |
|
impl_ref().push(move(agent)); |
36 |
39 |
} |
} |
37 |
40 |
} |
} |
38 |
41 |
} |
} |
39 |
42 |
|
|
40 |
43 |
///////////////////////////////////////////////////////////////////////////////////// |
///////////////////////////////////////////////////////////////////////////////////// |
41 |
|
template <typename... T> |
|
42 |
|
auto BatchImpl<T...>::elements() -> batch_type& |
|
|
44 |
|
template <template <typename> typename P, typename... T> |
|
45 |
|
auto BatchImpl<P, T...>::impl_ref() -> batch_type& |
43 |
46 |
{ |
{ |
44 |
|
return m_elements; |
|
|
47 |
|
return m_impl; |
45 |
48 |
} |
} |
46 |
49 |
|
|
47 |
50 |
///////////////////////////////////////////////////////////////////////////////////// |
///////////////////////////////////////////////////////////////////////////////////// |
48 |
|
template <typename... T> |
|
49 |
|
auto BatchImpl<T...>::elements() const -> const batch_type& |
|
|
51 |
|
template <template <typename> typename P, typename... T> |
|
52 |
|
auto BatchImpl<P, T...>::impl_ref() const -> const batch_type& |
50 |
53 |
{ |
{ |
51 |
|
return m_elements; |
|
|
54 |
|
return m_impl; |
52 |
55 |
} |
} |
53 |
56 |
} // control |
} // control |
54 |
57 |
} // om636 |
} // om636 |
File test/lib/dynamo/test/lib/circuit/README.md changed (mode: 100644) (index e8eeb01..7b85e05) |
1 |
|
## Objective |
|
|
1 |
|
# circuit |
2 |
2 |
|
|
3 |
|
Syncronize container operations (for single objects) |
|
|
3 |
|
Syncronize container operations for single objects |
4 |
4 |
|
|
5 |
5 |
## Interface |
## Interface |
|
6 |
|
``` |
|
7 |
|
#pragma once |
|
8 |
|
|
|
9 |
|
namespace om636 { |
|
10 |
|
namespace circuit { |
|
11 |
|
|
|
12 |
|
template <class T> |
|
13 |
|
struct Circuit { |
|
14 |
|
typedef T value_type; |
|
15 |
|
|
|
16 |
|
virtual ~Circuit() = default; |
|
17 |
|
virtual void push(value_type&&) = 0; |
|
18 |
|
virtual bool check_pop(value_type&) = 0; |
|
19 |
|
virtual void wait_pop(value_type&) = 0; |
|
20 |
|
virtual Circuit* clone() const = 0; |
|
21 |
|
}; |
|
22 |
|
|
|
23 |
|
} // circuit |
|
24 |
|
} // om636 |
6 |
25 |
|
|
7 |
26 |
``` |
``` |
8 |
|
circuit.check_pop(variable) |
|
9 |
|
circuit.wait_pop(variable) |
|
10 |
|
circuit.push(1); |
|
|
27 |
|
|
|
28 |
|
|
|
29 |
|
## Example |
11 |
30 |
``` |
``` |
|
31 |
|
#include <tmp/src/test.h> |
|
32 |
|
|
|
33 |
|
#include <lib/circuit/src/index.h> |
|
34 |
|
|
|
35 |
|
using namespace std; |
|
36 |
|
using namespace om636::circuit; |
|
37 |
|
|
|
38 |
|
int main() |
|
39 |
|
{ |
|
40 |
|
CircuitStack<int> s; |
|
41 |
|
|
|
42 |
|
s.push(88); |
|
43 |
|
s.push(77); |
|
44 |
|
|
|
45 |
|
int i; |
|
46 |
|
s.wait_pop(i); |
|
47 |
|
if (s.check_pop(i)) { |
|
48 |
|
|
|
49 |
|
} |
|
50 |
|
} |
|
51 |
|
``` |
|
52 |
|
|
File test/lib/dynamo/test/lib/circuit/src/impl/circuit_host.h changed (mode: 100644) (index be202e3..375f033) |
... |
... |
namespace circuit { |
17 |
17 |
using typename base_type::value_type; |
using typename base_type::value_type; |
18 |
18 |
|
|
19 |
19 |
CircuitHost() = default; |
CircuitHost() = default; |
|
20 |
|
CircuitHost(const CircuitHost&); |
20 |
21 |
CircuitHost(CircuitHost&&); |
CircuitHost(CircuitHost&&); |
21 |
22 |
CircuitHost& operator=(CircuitHost); |
CircuitHost& operator=(CircuitHost); |
22 |
23 |
|
|
|
... |
... |
namespace circuit { |
28 |
29 |
void push(value_type&&) override; |
void push(value_type&&) override; |
29 |
30 |
bool check_pop(value_type&) override; |
bool check_pop(value_type&) override; |
30 |
31 |
void wait_pop(value_type&) override; |
void wait_pop(value_type&) override; |
|
32 |
|
CircuitHost* clone() const override; |
31 |
33 |
|
|
32 |
34 |
private: |
private: |
33 |
35 |
typedef U<T> policy_type; |
typedef U<T> policy_type; |
File test/lib/dynamo/test/lib/circuit/src/impl/circuit_host.hxx changed (mode: 100644) (index 178dfb8..fdf9742) |
1 |
1 |
namespace om636 { |
namespace om636 { |
2 |
2 |
namespace circuit { |
namespace circuit { |
3 |
3 |
|
|
|
4 |
|
///////////////////////////////////////////////////////////////////////////////////////////// |
|
5 |
|
template <typename T, template <typename> class U> |
|
6 |
|
CircuitHost<T, U>::CircuitHost(const CircuitHost& rhs) |
|
7 |
|
{ |
|
8 |
|
typedef std::unique_lock<mutex_type> lock_type; |
|
9 |
|
|
|
10 |
|
lock_type left_lock(m_mutex, std::defer_lock); |
|
11 |
|
lock_type right_lock(rhs.m_mutex, std::defer_lock); |
|
12 |
|
std::lock(left_lock, right_lock); |
|
13 |
|
|
|
14 |
|
policy_type::on_copy(*this, rhs); |
|
15 |
|
} |
|
16 |
|
|
4 |
17 |
///////////////////////////////////////////////////////////////////////////////////////////// |
///////////////////////////////////////////////////////////////////////////////////////////// |
5 |
18 |
template <typename T, template <typename> class U> |
template <typename T, template <typename> class U> |
6 |
19 |
CircuitHost<T, U>::CircuitHost(CircuitHost&& rhs) |
CircuitHost<T, U>::CircuitHost(CircuitHost&& rhs) |
|
... |
... |
namespace circuit { |
48 |
61 |
bool result(false); |
bool result(false); |
49 |
62 |
std::thread([this, &result]() { |
std::thread([this, &result]() { |
50 |
63 |
result = m_mutex.try_lock(); |
result = m_mutex.try_lock(); |
51 |
|
if (result) { |
|
52 |
|
m_mutex.unlock(); |
|
|
64 |
|
if (result) { |
|
65 |
|
m_mutex.unlock(); |
53 |
66 |
} |
} |
54 |
67 |
}).join(); |
}).join(); |
55 |
68 |
return !result; |
return !result; |
|
... |
... |
namespace circuit { |
86 |
99 |
m_condition.wait(lock, [this] { return !policy_type::on_empty(*this); }); |
m_condition.wait(lock, [this] { return !policy_type::on_empty(*this); }); |
87 |
100 |
policy_type::on_pop(*this, value); |
policy_type::on_pop(*this, value); |
88 |
101 |
} |
} |
|
102 |
|
|
|
103 |
|
///////////////////////////////////////////////////////////////////////////////////////////// |
|
104 |
|
template <typename T, template <typename> class U> |
|
105 |
|
auto CircuitHost<T, U>::clone() const -> CircuitHost* |
|
106 |
|
{ |
|
107 |
|
return new CircuitHost(*this); |
|
108 |
|
} |
|
109 |
|
|
89 |
110 |
} // circuit |
} // circuit |
90 |
111 |
} // om636 |
} // om636 |
File test/lib/dynamo/test/src/batch.h changed (mode: 100644) (index 4097e88..47cff77) |
1 |
|
using namespace om636; |
|
|
1 |
|
#include <lib/circuit/src/impl/queue.h> |
|
2 |
|
|
2 |
3 |
using namespace om636::control; |
using namespace om636::control; |
|
4 |
|
using namespace om636; |
3 |
5 |
using namespace std; |
using namespace std; |
|
6 |
|
using namespace om636::circuit; |
4 |
7 |
|
|
5 |
8 |
void check_unhook_while_traverse() |
void check_unhook_while_traverse() |
6 |
9 |
{ |
{ |
7 |
|
BatchImpl<> batch; |
|
|
10 |
|
BatchImpl<QueuePolicy> batch; |
8 |
11 |
unsigned passed(0); |
unsigned passed(0); |
9 |
12 |
|
|
10 |
|
typename BatchImpl<>::listener_type temp(batch.hook([&]() { |
|
|
13 |
|
typename BatchImpl<QueuePolicy>::listener_type temp(batch.hook([&]() { |
11 |
14 |
++passed; |
++passed; |
12 |
15 |
temp.reset(); |
temp.reset(); |
13 |
16 |
})); |
})); |
|
... |
... |
void check_unhook_while_traverse() |
21 |
24 |
|
|
22 |
25 |
void dead_agent_removal() |
void dead_agent_removal() |
23 |
26 |
{ |
{ |
24 |
|
typedef BatchImpl<int> batch_type; |
|
|
27 |
|
typedef BatchImpl<QueuePolicy, int> batch_type; |
25 |
28 |
batch_type batch; |
batch_type batch; |
26 |
29 |
batch.hook([](int) {}); |
batch.hook([](int) {}); |
27 |
30 |
batch.invoke(9); |
batch.invoke(9); |
28 |
31 |
|
|
29 |
|
ASSERT(batch.elements().empty() && "dead agent removal"); |
|
|
32 |
|
ASSERT(batch.impl_ref().empty() && "dead agent removal"); |
30 |
33 |
} |
} |
31 |
34 |
|
|
32 |
35 |
void check_traverse_with_arg() |
void check_traverse_with_arg() |
33 |
36 |
{ |
{ |
34 |
|
BatchImpl<int> batch; |
|
|
37 |
|
BatchImpl<QueuePolicy, int> batch; |
35 |
38 |
int v = 0; |
int v = 0; |
36 |
39 |
auto p(batch.hook([&](int i) { |
auto p(batch.hook([&](int i) { |
37 |
40 |
v = i; |
v = i; |
|
... |
... |
void check_traverse_with_arg() |
44 |
47 |
|
|
45 |
48 |
void check_traverse_with_args() |
void check_traverse_with_args() |
46 |
49 |
{ |
{ |
47 |
|
typedef BatchImpl<int, int> batch_type; |
|
|
50 |
|
typedef BatchImpl<QueuePolicy, int, int> batch_type; |
48 |
51 |
|
|
49 |
52 |
unsigned test_passed(0); |
unsigned test_passed(0); |
50 |
53 |
batch_type batch; |
batch_type batch; |
|
... |
... |
void check_traverse_with_args() |
62 |
65 |
|
|
63 |
66 |
void check_traverse_while_traverse() |
void check_traverse_while_traverse() |
64 |
67 |
{ |
{ |
65 |
|
BatchImpl<> batch; |
|
|
68 |
|
BatchImpl<QueuePolicy> batch; |
66 |
69 |
unsigned passed(0); |
unsigned passed(0); |
67 |
70 |
|
|
68 |
71 |
auto p(batch.hook([&]() { |
auto p(batch.hook([&]() { |
|
... |
... |
void check_traverse_while_traverse() |
77 |
80 |
|
|
78 |
81 |
void check_traverse() |
void check_traverse() |
79 |
82 |
{ |
{ |
80 |
|
BatchImpl<> batch; |
|
|
83 |
|
BatchImpl<QueuePolicy> batch; |
81 |
84 |
unsigned passed(0); |
unsigned passed(0); |
82 |
85 |
|
|
83 |
86 |
auto temp(batch.hook([&]() { |
auto temp(batch.hook([&]() { |