transaction_dynamic_node_test.cpp
1 /*
2  * transaction_dynamic_node_test.cpp
3  *
4  * Test code of software transactional memory, for simultaneous transaction including
5  * insertion/removal/swap of object links on tree-structure objects.
6  */
7 
8 #include "support.h"
9 
10 //For inline expansion of lock-free custom new()/delete() operators.
11 //Comment out this and '#include "allocator.cpp"' in support.cpp to use the original operators.
12 #include "allocator.h"
13 
14 #include <stdint.h>
15 #include <thread>
16 
17 #include "transaction.h"
18 
19 #include "xthread.cpp"
20 
21 atomic<int> objcnt = 0; //# of living objects.
22 atomic<long> total = 0; //The sum of payloads.
23 
24 //#define TRANSACTIONAL_STRICT_assert
25 
26 class LongNode;
29 
30 class LongNode : public Transactional::Node<LongNode> {
31 public:
33  ++objcnt;
34  // trans(*this) = 0;
35  }
36  virtual ~LongNode() {
37  --objcnt;
38  }
39 
40  //! Data holder.
41  struct Payload : public Transactional::Node<LongNode>::Payload {
43  Payload(const Payload &x) : Transactional::Node<LongNode>::Payload(x), m_x(x.m_x) {
44  total += m_x;
45  }
46  virtual ~Payload() {
47  total -= m_x;
48  }
49  operator long() const {return m_x;}
50  Payload &operator=(const long &x) {
51  total += x - m_x;
52  m_x = x;
53  return *this;
54  }
55  Payload &operator+=(const long &x) {
56  total += x;
57  m_x += x;
58  return *this;
59  }
60  private:
61  long m_x;
62 // double load[10000];
63  };
64 };
65 
66 class ComplexNode : public LongNode {
67 public:
68  ComplexNode(Transaction &tr, shared_ptr<LongNode> &var) : LongNode(), m_var(var) {
69 // msecsleep(40);
70  m_1.reset(create<LongNode>());
71  insert(m_1);
72  var->insert(tr, m_1, false);
73 // msecsleep(40);
74 // m_2.reset(create<LongNode>());
75 // insert(m_2);
76 // m_3.reset(create<LongNode>());
77 // insert(m_3);
78 // m_4.reset(create<LongNode>());
79 // msecsleep(40);
80 // var->insert(tr, m_4);
81  }
82  virtual ~ComplexNode() {
83  m_var->release(m_1);
84 // m_var->release(m_4);
85  }
86  const shared_ptr<LongNode> &n1() const {return m_1;}
87 private:
88  const shared_ptr<LongNode> m_var;
89  shared_ptr<LongNode> m_1, m_2, m_3, m_4;
90 };
91 
92 #define trans(node) for(Transaction \
93  implicit_tr(node, false); !implicit_tr.isModified() || !implicit_tr.commitOrNext(); ) implicit_tr[node]
94 
95 template <class T>
96 typename std::enable_if<std::is_base_of<LongNode, T>::value,
97  const typename Transactional::SingleSnapshot<LongNode, T> >::type
98  operator*(T &node) {
100 }
101 
102 #include "transaction_impl.h"
103 template class Transactional::Node<LongNode>;
104 
105 shared_ptr<LongNode> gn1, gn2, gn3, gn4;
106 
107 void
108 start_routine(void) {
109  printf("start\n");
110  shared_ptr<LongNode> p1(LongNode::create<LongNode>());
111  shared_ptr<LongNode> p2(LongNode::create<LongNode>());
112  for(int i = 0; i < 2500; i++) {
113  p1->insert(p2);
114  if((i % 10) == 0) {
115  gn1->iterate_commit_if([=](Transaction &tr1)->bool{
116  if( !gn2->insert(tr1, p2))
117  return false;
118  return true;
119  });
120  gn2->swap(p2, gn3);
121  gn1->insert(p1);
122  }
123  // gn1->print_();
124  gn1->iterate_commit([=](Transaction &tr1){
125 // tr1.print();
126  Snapshot &ctr1(tr1); // For reading.
127  tr1[gn1] = ctr1[gn1] + 1;
128  tr1[gn3] = ctr1[gn3] + 1;
129  Snapshot &str1(tr1);
130  tr1[gn1] = str1[gn1] - 1;
131  tr1[gn2] = str1[gn2] + 1;
132  if((i % 10) == 0) {
133  tr1[p2] = str1[p2] + 1;
134  }
135 // printf("f");
136  });
137  trans(*gn3) += 1;
138  gn4->iterate_commit([=](Transaction &tr1){
139  tr1[gn4] = tr1[gn4] + 1;
140  tr1[gn4] = tr1[gn4] - 1;
141 // printf("f");
142  });
143  p1->release(p2);
144  gn2->iterate_commit([=](Transaction &tr1){
145  Snapshot &str1(tr1);
146  tr1[gn2] = tr1[gn2] - 1;
147  tr1[gn3] = str1[gn3] - 1;
148  if((i % 10) == 0) {
149  tr1[p2] = str1[p2] - 1;
150  }
151 // printf("f");
152  });
153  trans(*gn3) += -1;
154  if((i % 10) == 0) {
155  gn1->iterate_commit_if([=](Transaction &tr1)->bool{
156  if( !gn2->release(tr1, p2))
157  return false;
158  return true;
159  });
160  gn1->release(p1);
161  }
162  }
163  long y = ***p2;
164  if(y != 0) {
165  printf("Error! P2=%ld\n", y);
166  abort();
167  }
168  else
169  printf("finish\n");
170  return;
171 }
172 
173 #define NUM_THREADS 4
174 
175 int
176 main(int argc, char **argv) {
177  for(int k = 0; k < 100; k++) {
178  gn1.reset(LongNode::create<LongNode>());
179  gn2.reset(LongNode::create<LongNode>());
180  gn3.reset(LongNode::create<LongNode>());
181  gn4.reset(LongNode::create<LongNode>());
182 
183  gn1->iterate_commit_if([=](Transaction &tr1)->bool{
184  printf("1");
185  if( !gn1->insert(tr1, gn2, true))
186  return false;
187  tr1[ *gn2] = tr1[ *gn2] + 1;
188  if( !gn2->insert(tr1, gn3, true))
189  return false;
190  tr1.print();
191  if( !gn3->insert(tr1, gn4, true))
192  return false;
193  tr1.print();
194  if( !gn3->release(tr1, gn4))
195  return false;
196  tr1.print();
197  return true;
198  });
199  gn1->print_();
200  gn1->release(gn2);
201  gn1->print_();
202  gn1->insert(gn2);
203  gn1->print_();
204  gn2->iterate_commit([=](Transaction &tr1){
205  printf("2");
206  tr1[ *gn2] = tr1[ *gn2] - 1;
207  tr1[ *gn3] = 0;
208  });
209  {
210  Snapshot shot1(*gn1);
211  shot1.print();
212  long x = shot1[*gn3];
213  printf("Gn3:%ld\n", x);
214  }
215  trans(*gn3) = 3;
216  long x = ***gn3;
217  printf("Gn3:%ld\n", x);
218  trans(*gn3) = 0;
219 
220  shared_ptr<LongNode> p1(LongNode::create<LongNode>());
221  gn3->insert(p1);
222  gn1->insert(p1);
223  gn1->swap(p1, gn2);
224  trans(*gn1) = 3;
225  trans(*gn1) = 0;
226 
227  {
228  shared_ptr<LongNode> p2(LongNode::create<LongNode>());
229  shared_ptr<LongNode> p22(LongNode::create<LongNode>());
230  shared_ptr<LongNode> p211(LongNode::create<LongNode>());
231  shared_ptr<LongNode> p21(LongNode::create<LongNode>());
232  p2->insert(p21);
233  p21->insert(p211);
234  p2->insert(p211);
235  trans(*p211) = 1;
236  p21->insert(p22);
237  p211->insert(p22);
238 
239  gn1->insert(p2);
240  gn3->insert(p2);
241  gn1->release(p2);
242  gn3->release(p2);
243 
244  shared_ptr<ComplexNode> p2111;
245 
246  gn3->iterate_commit_if([=, &p2111](Transaction &tr1)->bool{
247  printf("3");
248  if( !p1->insert(tr1, p22, true))
249  return false;
250  if( !gn3->insert(tr1, p2, true))
251  return false;
252 
253  p2111.reset(LongNode::create<ComplexNode>(ref(tr1), gn3));
254  shared_ptr<LongNode> p2112(LongNode::create<LongNode>());
255  shared_ptr<LongNode> p2113(LongNode::create<LongNode>());
256  shared_ptr<LongNode> p2114(LongNode::create<LongNode>());
257  p2111->insert(p2112);
258  p2112->insert(p2113);
259  p2111->insert(p2114);
260  trans( *p2113) = 1;
261  trans( *p2114) = 1;
262 
263  if( !p21->insert(tr1, p2111, true))
264  return false;
265  if( !gn3->insert(tr1, p2111, true))
266  return false;
267 
268  tr1[ *p2113] = 0;
269  tr1[ *p2114] = 0;
270 
271  tr1[*p22] = 1;
272  return true;
273  });
274  {
275  Snapshot shot1(*gn3);
276  shot1[ *p2111->n1()];
277  }
278  gn1->iterate_commit_if([=](Transaction &tr1)->bool{
279  printf("4");
280  if( !gn3->insert(tr1, gn4, true))
281  return false;
282  if( !gn2->insert(tr1, gn4, true))
283  return false;
284  return true;
285  });
286  gn1->iterate_commit_if([=](Transaction &tr1)->bool{
287  printf("5");
288  if( !gn3->release(tr1, gn4))
289  return false;
290  if( !gn2->release(tr1, gn4))
291  return false;
292  return true;
293  });
294  {
295  Snapshot shot1(*gn3);
296  shot1[ *p2];
297  shot1[ *p21];
298  shot1[ *p22];
299  }
300  trans(*p211) = 0;
301  gn3->iterate_commit_if([=](Transaction &tr1)->bool{
302  if( !p1->release(tr1, p22))
303  return false;
304  if( !gn3->release(tr1, p2))
305  return false;
306  if( !gn3->release(tr1, p2111))
307  return false;
308  return true;
309  });
310  trans(*p22) = 0;
311 
312  gn1->iterate_commit([=](Transaction &tr1){
313  Snapshot &ctr1(tr1); // For reading.
314  tr1[gn1] = ctr1[gn1] + 1;
315  tr1[gn3] = ctr1[gn3] + 1;
316  Snapshot &str1(tr1);
317  tr1[gn1] = str1[gn1] - 1;
318  tr1[gn3] = str1[gn3] - 1;
319  });
320  }
321  gn1->print_();
322  gn1->release(p1);
323  gn1->print_();
324 
325  std::thread threads[NUM_THREADS];
326 
327  for(int i = 0; i < NUM_THREADS; i++) {
328  std::thread th( &start_routine);
329  threads[i].swap(th);
330  }
331  msecsleep(10);
332  for(int i = 0; i < 100; i++) {
333  gn3->insert(gn4);
334  gn3->release(gn4);
335  }
336  for(int i = 0; i < NUM_THREADS; i++) {
337  threads[i].join();
338  }
339  printf("join\n");
340 
341  if(***gn1 || ***gn2 || ***gn3 || ***gn4) {
342  printf("failed1\n");
343  printf("Gn1:%ld\n", (long)***gn1);
344  printf("Gn2:%ld\n", (long)***gn2);
345  printf("Gn3:%ld\n", (long)***gn3);
346  printf("Gn4:%ld\n", (long)***gn4);
347  return -1;
348  }
349 
350  gn1.reset();
351  gn2.reset();
352  gn3.reset();
353  gn4.reset();
354  p1.reset();
355 
356  if(objcnt != 0) {
357  printf("failed1\n");
358  return -1;
359  }
360  if(total != 0) {
361  printf("failed total=%ld\n", (long)total);
362  return -1;
363  }
364  }
365  printf("succeeded\n");
366  return 0;
367 }

Generated for KAME4 by  doxygen 1.8.3