24 #ifndef GRAPHLAB_LOCAL_CHANDY_MISRA_HPP
25 #define GRAPHLAB_LOCAL_CHANDY_MISRA_HPP
27 #include <graphlab/logger/assertions.hpp>
28 #include <graphlab/parallel/pthread_tools.hpp>
29 #include <graphlab/parallel/atomic.hpp>
30 #include <graphlab/macros_def.hpp>
33 template <
typename GraphType>
44 std::vector<unsigned char> forkset;
49 enum {OWNER_SOURCE = 0, OWNER_TARGET = 1};
50 inline unsigned char request_bit(
bool owner) {
51 return owner ? REQUEST_1 : REQUEST_0;
56 atomic<vertex_id_type> forks_acquired;
60 if (num_edges == forks_acquired.value) {
62 (
unsigned char)HUNGRY,
63 (
unsigned char)EATING);
68 std::vector<philosopher> philosopherset;
79 inline void request_for_fork(
size_t forkid,
bool nextowner) {
80 forkset[forkid] |= request_bit(nextowner);
83 inline bool fork_owner(
size_t forkid) {
84 return forkset[forkid] & OWNER_BIT;
87 inline bool fork_dirty(
size_t forkid) {
88 return !!(forkset[forkid] & DIRTY_BIT);
91 inline void dirty_fork(
size_t forkid) {
92 forkset[forkid] |= DIRTY_BIT;
99 inline bool advance_fork_state_on_lock(
size_t forkid,
103 unsigned char currentowner = forkset[forkid] & OWNER_BIT;
105 unsigned char my_request_bit = request_bit(currentowner);
106 unsigned char other_request_bit = request_bit(!currentowner);
108 bool current_owner_is_eating =
109 (currentowner == OWNER_SOURCE && philosopherset[source].state == EATING) ||
110 (currentowner == OWNER_TARGET && philosopherset[target].state == EATING);
111 bool current_owner_is_hungry =
112 (currentowner == OWNER_SOURCE && philosopherset[source].state == HUNGRY) ||
113 (currentowner == OWNER_TARGET && philosopherset[target].state == HUNGRY);
117 if (current_owner_is_eating ==
false &&
118 (forkset[forkid] & DIRTY_BIT) &&
119 (forkset[forkid] & other_request_bit)) {
122 forkset[forkid] = (!currentowner);
123 if (current_owner_is_hungry) {
124 forkset[forkid] |= my_request_bit;
132 inline bool advance_fork_state_on_unlock(
size_t forkid,
136 unsigned char currentowner = forkset[forkid] & OWNER_BIT;
138 unsigned char my_request_bit = request_bit(currentowner);
139 unsigned char other_request_bit = request_bit(!currentowner);
143 if ((forkset[forkid] & DIRTY_BIT) &&
144 (forkset[forkid] & other_request_bit)) {
147 forkset[forkid] = (forkset[forkid] & my_request_bit) | (!currentowner);
153 void compute_initial_fork_arrangement() {
155 philosopherset[i].num_edges = graph.num_in_edges(i) +
156 graph.num_out_edges(i);
157 philosopherset[i].state = THINKING;
158 foreach(
typename GraphType::edge_type edge, graph.in_edges(i)) {
159 if (edge.source() > edge.target()) {
160 forkset[graph.edge_id(edge)] = DIRTY_BIT | 1;
163 forkset[graph.edge_id(edge)] = DIRTY_BIT;
177 philosopherset[v2].lock.lock();
179 else if (!philosopherset[v2].lock.try_lock()) {
180 philosopherset[v1].lock.unlock();
181 philosopherset[v2].lock.lock();
182 philosopherset[v1].lock.lock();
188 inline chandy_misra(GraphType &graph):graph(graph) {
189 forkset.resize(graph.num_edges(), 0);
190 philosopherset.resize(graph.num_vertices());
191 compute_initial_fork_arrangement();
200 philosopherset[p_id].lock.lock();
201 philosopherset[p_id].forks_acquired.value = 0;
203 ASSERT_EQ((
int)philosopherset[p_id].state, (
int)THINKING);
204 philosopherset[p_id].state = HUNGRY;
210 foreach(
typename GraphType::edge_type edge, graph.in_edges(p_id)) {
211 try_acquire_edge_with_backoff(edge.target(), edge.source());
213 size_t edgeid = graph.edge_id(edge);
215 if (fork_owner(edgeid) == OWNER_SOURCE) {
216 request_for_fork(edgeid, OWNER_TARGET);
218 philosopherset[p_id].forks_acquired.inc(
219 advance_fork_state_on_lock(edgeid, edge.source(), edge.target()));
222 philosopherset[p_id].forks_acquired.inc();
224 philosopherset[edge.source()].lock.unlock();
227 foreach(
typename GraphType::edge_type edge, graph.out_edges(p_id)) {
229 try_acquire_edge_with_backoff(edge.source(), edge.target());
230 size_t edgeid = graph.edge_id(edge);
233 if (fork_owner(edgeid) == OWNER_TARGET) {
234 request_for_fork(edgeid, OWNER_SOURCE);
235 philosopherset[p_id].forks_acquired.inc(
236 advance_fork_state_on_lock(edgeid, edge.source(), edge.target()));
239 philosopherset[p_id].forks_acquired.inc();
241 philosopherset[edge.target()].lock.unlock();
245 if (philosopherset[p_id].atomic_eat()) {
249 philosopherset[p_id].lock.unlock();
253 inline std::vector<vertex_id_type> philosopher_stops_eating(
size_t p_id) {
254 std::vector<vertex_id_type> retval;
255 philosopherset[p_id].lock.lock();
257 ASSERT_EQ((
int)philosopherset[p_id].state, (
int)EATING);
259 foreach(
typename GraphType::edge_type edge, graph.in_edges(p_id)) {
261 size_t edgeid = graph.edge_id(edge);
264 philosopherset[other].forks_acquired.inc(
265 advance_fork_state_on_unlock(edgeid, edge.source(), edge.target()));
266 if (philosopherset[other].atomic_eat()) {
268 retval.push_back(other);
273 foreach(
typename GraphType::edge_type edge, graph.out_edges(p_id)) {
275 size_t edgeid = graph.edge_id(edge);
278 philosopherset[other].forks_acquired.inc(
279 advance_fork_state_on_unlock(edgeid, edge.source(), edge.target()));
280 if (philosopherset[other].atomic_eat()) {
282 retval.push_back(other);
286 philosopherset[p_id].state = THINKING;
288 philosopherset[p_id].lock.unlock();
292 void no_locks_consistency_check() {
294 for (
size_t i = 0;i < forkset.size(); ++i) ASSERT_TRUE(fork_dirty(i));
296 for (
size_t i = 0;i < philosopherset.size(); ++i) ASSERT_TRUE(philosopherset[i].state == THINKING);
299 void complete_consistency_check() {
303 size_t numowned_clean = 0;
304 foreach(
typename GraphType::edge_type edge, graph.in_edges(v)) {
305 size_t edgeid = graph.edge_id(edge);
306 if (fork_owner(edgeid) == OWNER_TARGET) {
308 if (!fork_dirty(edgeid)) numowned_clean++;
311 foreach(
typename GraphType::edge_type edge, graph.out_edges(v)) {
312 size_t edgeid = graph.edge_id(edge);
313 if (fork_owner(edgeid) == OWNER_SOURCE) {
315 if (!fork_dirty(edgeid)) numowned_clean++;
319 if (philosopherset[v].state == THINKING) {
320 ASSERT_EQ(numowned_clean, 0);
322 else if (philosopherset[v].state == HUNGRY) {
323 ASSERT_EQ(philosopherset[v].forks_acquired.value, numowned);
325 else if (philosopherset[v].state == EATING) {
326 ASSERT_EQ(philosopherset[v].forks_acquired.value, philosopherset[v].num_edges);
327 ASSERT_EQ(philosopherset[v].forks_acquired.value, numowned);
335 #include <graphlab/macros_undef.hpp>