transaction_negotiation_test.cpp
1 /*
2  * transaction_negotiation_test.cpp
3  *
4  * Test code of software transactional memory, for simultaneous transaction with different periodicities.
5  * The slower transaction would never succeed unless a proper wait is put on the faster loop.
6  */
7 
8 #include "support.h"
9 
10 
11 //For inline expansion of lock-free custom new()/delete() operators.
12 //Comment out this and '#include "allocator.cpp"' in support.cpp to use the original operators.
13 #include "allocator.h"
14 
15 #include <stdint.h>
16 #include <thread>
17 
18 #include "transaction.h"
19 
20 #include "xthread.cpp"
21 
22 atomic<int> slow_threads = 0;
23 atomic<int> objcnt = 0; //# of objects.
24 atomic<long> total = 0; //The sum of payloads.
25 
26 #define TRANSACTIONAL_STRICT_assert
27 
28 class LongNode : public Transactional::Node<LongNode> {
29 public:
30  LongNode() : Transactional::Node<LongNode>() {
31  ++objcnt;
32  // trans(*this) = 0;
33  }
34  virtual ~LongNode() {
35  --objcnt;
36  }
37 
38  //! Data holder.
39  struct Payload : public Transactional::Node<LongNode>::Payload {
40  Payload() : Transactional::Node<LongNode>::Payload(), m_x(0) {}
41  Payload(const Payload &x) : Transactional::Node<LongNode>::Payload(x), m_x(x.m_x) {
42  total += m_x;
43  }
44  virtual ~Payload() {
45  total -= m_x;
46  }
47  operator long() const {return m_x;}
48  Payload &operator=(const long &x) {
49  total += x - m_x;
50  m_x = x;
51  return *this;
52  }
53  Payload &operator+=(const long &x) {
54  total += x;
55  m_x += x;
56  return *this;
57  }
58  private:
59  long m_x;
60  };
61 };
62 
65 
66 #define trans(node) for(Transaction \
67  implicit_tr(node, false); !implicit_tr.isModified() || !implicit_tr.commitOrNext(); ) implicit_tr[node]
68 
69 template <class T>
70 typename std::enable_if<std::is_base_of<LongNode, T>::value,
71  const typename Transactional::SingleSnapshot<LongNode, T> >::type
72  operator*(T &node) {
74 }
75 
76 #include "transaction_impl.h"
77 template class Transactional::Node<LongNode>;
78 
79 shared_ptr<LongNode> gn1, gn2, gn3, gn4;
80 
81 #define NUM_SLOW_THREADS 2
82 #define NUM_THREADS 6
83 
84 void
85 start_routine(int th_no) {
86  printf("start\n");
87 
88  int lps = 5000000;
89  bool wait = false;
90  if(th_no < NUM_SLOW_THREADS) {
91  ++slow_threads;
92  lps = 10;
93  wait = true;
94  }
95 
96  shared_ptr<LongNode> p1(LongNode::create<LongNode>());
97  shared_ptr<LongNode> p2(LongNode::create<LongNode>());
98  for(int i = 0; i < lps; i++) {
99  if( !slow_threads)
100  break;
101  p1->insert(p2);
102  if((i % 10) == 0) {
103  gn2->insert(p2);
104  gn2->swap(p2, gn3);
105  gn1->insert(p1);
106  }
107  gn1->iterate_commit([=](Transaction &tr1){
108  Snapshot &ctr1(tr1); // For reading.
109  tr1[gn1] = ctr1[gn1] + 1;
110  tr1[gn3] = ctr1[gn3] + 1;
111  Snapshot &str1(tr1);
112  tr1[gn1] = str1[gn1] - 1;
113  tr1[gn2] = str1[gn2] + 1;
114  if((i % 10) == 0) {
115  tr1[p2] = str1[p2] + 1;
116  }
117  if(wait) msecsleep(10);
118 // printf("f");
119  });
120  trans(*gn3) += 1;
121  gn4->iterate_commit([=](Transaction &tr1){
122  tr1[gn4] = tr1[gn4] + 1;
123  tr1[gn4] = tr1[gn4] - 1;
124  if(wait) msecsleep(30);
125 // printf("f");
126  });
127  p1->release(p2);
128  gn2->iterate_commit([=](Transaction &tr1){
129  Snapshot &str1(tr1);
130  tr1[gn2] = tr1[gn2] - 1;
131  tr1[gn3] = str1[gn3] - 1;
132  if((i % 10) == 0) {
133  tr1[p2] = str1[p2] - 1;
134  }
135  if(wait) msecsleep(60);
136 // printf("f");
137  });
138  trans(*gn3) += -1;
139  if((i % 10) == 0) {
140  gn2->release(p2);
141  gn1->release(p1);
142  }
143  }
144  long y = ***p2;
145  if(y != 0) {
146  printf("Error! P2=%ld\n", y);
147  abort();
148  }
149  else
150  printf("finish no=%d\n", th_no);
151  if(th_no < NUM_SLOW_THREADS) {
152  --slow_threads;
153  }
154  return;
155 }
156 
157 int
158 main(int argc, char **argv)
159 {
160  for(int k = 0; k < 1; k++) {
161  gn1.reset(LongNode::create<LongNode>());
162  gn2.reset(LongNode::create<LongNode>());
163  gn3.reset(LongNode::create<LongNode>());
164  gn4.reset(LongNode::create<LongNode>());
165 
166  gn1->insert(gn2);
167  Snapshot shot1(*gn2);
168  gn2->insert(gn3);
169  {
170  Snapshot shot1(*gn1);
171  shot1.print();
172  long x = shot1[*gn3];
173  printf("Gn3:%ld\n", x);
174  }
175  trans(*gn3) = 3;
176  long x = ***gn3;
177  printf("Gn3:%ld\n", x);
178  trans(*gn3) = 0;
179 
180  shared_ptr<LongNode> p1(LongNode::create<LongNode>());
181  gn1->insert(p1);
182  gn1->swap(p1, gn2);
183  gn3->insert(p1);
184  trans(*gn1) = 3;
185  trans(*gn1) = 0;
186 
187  {
188  shared_ptr<LongNode> p2(LongNode::create<LongNode>());
189  shared_ptr<LongNode> p21(LongNode::create<LongNode>());
190  shared_ptr<LongNode> p22(LongNode::create<LongNode>());
191  shared_ptr<LongNode> p211(LongNode::create<LongNode>());
192  p2->insert(p21);
193  p21->insert(p211);
194  p2->print_();
195  p21->print_();
196  p211->print_();
197  p2->insert(p211);
198  p21->insert(p22);
199  p211->insert(p22);
200  {
201  Snapshot shot1(*p21);
202  shot1[ *p21];
203  shot1[ *p22];
204  shot1[ *p211];
205  }
206  long x = ***p2;
207  trans(*p22) = 1;
208  trans(*p22) = 0;
209  trans(*p21) = 1;
210  trans(*p21) = 0;
211  trans(*p211) = 1;
212  trans(*p211) = 0;
213  trans(*p2) = 1;
214  trans(*p2) = 0;
215 
216  gn1->iterate_commit([=](Transaction &tr1){
217  Snapshot &ctr1(tr1); // For reading.
218  tr1[gn1] = ctr1[gn1] + 1;
219  tr1[gn3] = ctr1[gn3] + 1;
220  Snapshot &str1(tr1);
221  tr1[gn1] = str1[gn1] - 1;
222  tr1[gn3] = str1[gn3] - 1;
223 // printf("f");
224  });
225  }
226  gn1->release(p1);
227 
228  std::thread threads[NUM_THREADS];
229 
230  for(int i = 0; i < NUM_THREADS; i++) {
231  std::thread th( &start_routine, i);
232  threads[i].swap(th);
233  }
234  {
235  msecsleep(1);
236  gn3->insert(gn4);
237  msecsleep(1);
238  gn3->release(gn4);
239  }
240  for(int i = 0; i < NUM_THREADS; i++) {
241  threads[i].join();
242  }
243  printf("join\n");
244 
245  if(***gn1 || ***gn2 || ***gn3 || ***gn4) {
246  printf("failed1\n");
247  printf("Gn1:%ld\n", (long)***gn1);
248  printf("Gn2:%ld\n", (long)***gn2);
249  printf("Gn3:%ld\n", (long)***gn3);
250  printf("Gn4:%ld\n", (long)***gn4);
251  return -1;
252  }
253 
254  gn1.reset();
255  gn2.reset();
256  gn3.reset();
257  gn4.reset();
258  p1.reset();
259 
260  if(objcnt != 0) {
261  printf("failed1\n");
262  return -1;
263  }
264  if(total != 0) {
265  printf("failed total=%ld\n", (long)total);
266  return -1;
267  }
268  }
269  printf("succeeded\n");
270  return 0;
271 }

Generated for KAME4 by  doxygen 1.8.3