source: CIVL/examples/compare/queue/NonBlockingQueue.cvl@ 449bd3f

1.23 2.0 main test-branch
Last change on this file since 449bd3f was 38a754a, checked in by Si Li <sili@…>, 11 years ago

add tests to NonBlockingQueue.cvl

git-svn-id: svn://vsl.cis.udel.edu/civl/trunk@2559 fb995dde-84ed-4084-dfe6-e5aef3e2452c

  • Property mode set to 100644
File size: 5.5 KB
RevLine 
[38a754a]1/* Non-Blocking Concurrent Queue Algorithm from Michael and Scott
2 * https://www.cs.rochester.edu/research/synchronization/pseudocode/queues.html.
3 * Originally from "Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms", PODC96.
4 */
5
6#include <civlc.cvh>
7#include <stdio.h>
8#include <stdbool.h>
9#include <stdlib.h>
10#include <assert.h>
11
12typedef struct pointer_t pointer_t;
13typedef struct queue_t queue_t;
14typedef struct node_t node_t;
15
16struct node_t;
17
18struct pointer_t {
19 node_t* ptr;
20 int count;
21};
22
23struct node_t {
24 int value;
25 pointer_t next;
26};
27
28struct queue_t {
29 pointer_t Head;
30 pointer_t Tail;
31};
32
33void initialize(queue_t *Q) {
34 node_t *node = (node_t*)malloc(sizeof(node_t)); // Allocate a free node
35
36 node->next.ptr = NULL; // Make it the only node in the linked list
37 node->next.count = 0; // Initialize counter
38 Q->Head.ptr = Q->Tail.ptr = node; // Both Head and Tail point to it
39}
40
41_Bool equal(pointer_t p1, pointer_t p2){ //define equal() method to compare two pointers
42 return (p1.ptr == p2.ptr) && (p1.count == p2.count);
43}
44
45_Bool CAS(pointer_t *dest, pointer_t oldval, pointer_t newval) //define CAS() method
46{
47 $atomic {
48 if (equal(*dest, oldval)) {
49 *dest = newval;
50 return true;
51 }
52 return false;
53 }
54}
55
56void enqueue(queue_t *Q, int value) {
57 pointer_t tail, next;
58 node_t *node = (node_t*)malloc(sizeof(node_t)); // Allocate a new node from the free list
59
60 node->value = value; // Copy enqueued value into node
61 node->next.ptr = NULL; // Set next pointer of node to NULL
62
63 while (true){ // Keep trying until Enqueue is done
64 tail = Q->Tail; // Read Tail.ptr and Tail.count together
65 next = tail.ptr->next; // Read next ptr and count fields together
66 if (equal(tail, Q->Tail)) // Are tail and next consistent?
67 // Was Tail pointing to the last node?
68 if (next.ptr == NULL){
69 // Try to link node at the end of the linked list
70 if (CAS(&tail.ptr->next, next, (pointer_t){ node, next.count + 1 }))
71 break; // **Enqueue is done. Exit loop
72 }
73 else{ // Tail was not pointing to the last node
74 // Try to swing Tail to the next node
75 CAS(&Q->Tail, tail, (pointer_t){ next.ptr, tail.count + 1 });
76 }
77 }
78 // Enqueue is done. Try to swing Tail to the inserted node
79 CAS(&Q->Tail, tail, (pointer_t){ node, tail.count + 1 });
80}
81
82_Bool dequeue(queue_t *Q, int *pvalue) { //boolean type
83 pointer_t head, tail, next;
84
85 while (true){ // Keep trying until Dequeue is done
86 head = Q->Head; // Read Head
87 tail = Q->Tail; // Read Tail
88 next = head.ptr->next; // Read Head.ptr->next
89 if (equal(head, Q->Head)) // Are head, tail, and next consistent?
90 if (head.ptr == tail.ptr){ // Is queue empty or Tail falling behind?
91 if (next.ptr == NULL) // Is queue empty?
92 return false; // Queue is empty, couldn't dequeue
93 // Tail is falling behind. Try to advance it
94 CAS(&Q->Tail, tail, (pointer_t){ next.ptr, tail.count + 1 });
95 }
96 else{
97 // Read value before CAS
98 // Otherwise, another dequeue might free the next node
99 *pvalue = next.ptr->value;
100 if (CAS(&Q->Head, head, (pointer_t){ next.ptr, head.count + 1 }))
101 break;// **Dequeue is done. Exit loop
102 }
103 }
104 free(head.ptr); // It is safe now to free the old node
105 return true; // Queue was not empty, dequeue succeeded
106}
107
108void test1() { // Test enqueue & dequeue
109 int d;
110 queue_t sq;
111
112 initialize(&sq);
113 for (int i = 0; i < 10; i++) {
114 enqueue(&sq, i);
115 }
116 for (int i = 0; i < 10; i++) {
117 _Bool result = dequeue(&sq, &d);
118
119 assert(result);
120 assert(d == i);
121 }
122 free(sq.Head.ptr);
123}
124
125void test2() { //Test the concurrency
126 queue_t sq;
127 int array[3];
128 void thread(int val) {enqueue(&sq, val);dequeue(&sq, &array[val-1]);}
129 int x, y, z;
130
131 initialize(&sq);
132
133 $parfor(int i: 1 .. 3)
134 thread(i);
135
136 for(int j=0; j<3; j++)
137 printf("array[%d] = %d\t",j, array[j]);
138 printf("\n");
139
140
141 assert((x==1&&y==2&&z==3)||(x==1&&y==3&&z==2)||
142 (x==2&&y==3&&z==1)||(x==2&&y==1&&z==3)||
143 (x==3&&y==1&&z==2)||(x==3&&y==2&&z==1));
144
145 //assert(!(x==3&&y==2&&z==0));
146
147 free(sq.Head.ptr);
148}
149
150void test3() { //Test the concurrency
151 queue_t sq;
152 int array[3];
153 void threadEn(int val) {enqueue(&sq, val);}
154 void threadDe(int val) {dequeue(&sq, &array[val-1]);}
155 int x, y, z;
156
157 initialize(&sq);
158
159 $parfor(int i: 1 .. 3)
160 threadEn(i);
161
162 $parfor(int i: 1 .. 3)
163 threadDe(i);
164
165 for(int j=0; j<3; j++)
166 printf("array[%d] = %d\t",j, array[j]);
167 printf("\n");
168
169 free(sq.Head.ptr);
170}
171
172#define N 2
173#define T 2
174void test4() { //Test 3
175 int RESULT[T][N];
176 int A[N];
177 queue_t sq;
178 printf("This is test3!\n");
179
180 void thread(int tid){
181 for(int i=0; i<N; i++)
182 enqueue(&sq, A[i]+tid*N);
183 for(int i=0; i<N; i++){
184 dequeue(&sq, &(RESULT[tid][i]));
185 printf("%d\n",RESULT[tid][i]);
186 }
187 }
188
189 for(int i=0; i<N; i++)
190 A[i] = i+1;
191 for(int i=0; i<T; i++)
192 for(int j=0; j<N; j++)
193 RESULT[i][j] = 0;
194 initialize(&sq);
195 $parfor(int i: 0 .. T-1)
196 thread(i);
197
198 //assert(!(RESULT[][]));
199 free(sq.Head.ptr);
200}
201
202void test5(){
203 queue_t sq;
204 void thread(int val) {enqueue(&sq, val);}
205 int x, y, z;
206
207 initialize(&sq);
208
209 $parfor(int i:1 .. 3)
210 thread(i);
211
212 dequeue(&sq, &x);
213 dequeue(&sq, &y);
214 dequeue(&sq, &z);
215
216 assert((x==1&&y==2&&z==3)||(x==1&&y==3&&z==2)||
217 (x==2&&y==3&&z==1)||(x==2&&y==1&&z==3)||
218 (x==3&&y==1&&z==2)||(x==3&&y==2&&z==1));
219
220 free(sq.Head.ptr);
221
222}
223
224void main() {
225 //test1();
226 test2();
227 //test3();
228}
229
230
231
232
233
Note: See TracBrowser for help on using the repository browser.