source: CIVL/examples/compare/queue/NonBlockingQueue_mc.cvl@ 5bc08d6

1.23 2.0 main test-branch
Last change on this file since 5bc08d6 was e221342, checked in by Manchun Zheng <zmanchun@…>, 11 years ago

added a fixed version for NonBlockingQueue.cvl

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

  • Property mode set to 100644
File size: 4.5 KB
Line 
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 count
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 {
49 if (equal(*dest, oldval)) {
50 *dest = newval;
51 return true;
52 }
53 return false;
54 }
55}
56
57void enqueue(queue_t *Q, int value) {
58 pointer_t tail, next;
59 node_t *node = (node_t*)malloc(sizeof(node_t)); // Allocate a new node from the free list
60
61 node->value = value; // Copy enqueued value into node
62 node->next.ptr = NULL; // Set next pointer of node to NULL
63
64 while (true){ // Keep trying until Enqueue is done
65 tail = Q->Tail; // Read Tail.ptr and Tail.count together
66 next = tail.ptr->next; // Read next ptr and count fields together
67 if (equal(tail, Q->Tail)) // Are tail and next consistent?
68 // Was Tail pointing to the last node?
69 if (next.ptr == NULL){
70 // Try to link node at the end of the linked list
71 if (CAS(&tail.ptr->next, next, (pointer_t){ node, next.count + 1 }))
72 break; // **Enqueue is done. Exit loop
73 }
74 else{// Tail was not pointing to the last node
75 // Try to swing Tail to the next node
76 CAS(&Q->Tail, tail, (pointer_t){ next.ptr, tail.count + 1 });
77 }
78 }
79 // Enqueue is done. Try to swing Tail to the inserted node
80 CAS(&Q->Tail, tail, (pointer_t){ node, tail.count + 1 });
81}
82
83_Bool dequeue(queue_t *Q, int *pvalue) { //boolean type
84 pointer_t head, tail, next;
85
86 while (true){ // Keep trying until Dequeue is done
87 head = Q->Head; // Read Head
88 tail = Q->Tail; // Read Tail
89 next = head.ptr->next; // Read Head.ptr->next
90 if (equal(head, Q->Head)) // Are head, tail, and next consistent?
91 if (head.ptr == tail.ptr){ // Is queue empty or Tail falling behind?
92 if (next.ptr == NULL) // Is queue empty?
93 return false; // Queue is empty, couldn't dequeue
94 // Tail is falling behind. Try to advance it
95 CAS(&Q->Tail, tail, (pointer_t){ next.ptr, tail.count + 1 });
96 }
97 else{
98 // Read value before CAS
99 // Otherwise, another dequeue might free the next node
100 *pvalue = next.ptr->value;
101 if (CAS(&Q->Head, head, (pointer_t){ next.ptr, head.count + 1 }))
102 break;// **Dequeue is done. Exit loop
103 }
104 }
105 free(head.ptr); // It is safe now to free the old node
106 return true; // Queue was not empty, dequeue succeeded
107}
108
109void test1() { // Test the functions
110 int i, d;
111 queue_t sq;
112 initialize(&sq);
113
114 for (i = 0; i < 10; i++){
115 enqueue(&sq, i);
116 }
117
118 while (sq.Head.ptr != sq.Tail.ptr)
119 {
120 dequeue(&sq, &d);
121 printf("%d ", d);
122 }
123 printf("\n");
124
125 assert(0==dequeue(&sq, &d));
126
127 free(sq.Head.ptr);
128}
129
130void test2(){
131 queue_t sq;
132 $proc t1, t2;
133 void thread(int val) {enqueue(&sq, val);}
134 int x, y;
135
136 initialize(&sq);
137 t1 = $spawn thread(1);
138 t2 = $spawn thread(2);
139 $wait(t1);
140 $wait(t2);
141 dequeue(&sq, &x);
142 dequeue(&sq, &y);
143
144 assert((x==1&&y==2)||(x==2&&y==1));
145
146 free(sq.Head.ptr);
147
148}
149
150#define N 2
151#define T 2
152$output int RESULT[T][N];
153int A[N];
154queue_t queue;
155
156void thread(int tid){
157 for(int i=0; i<N; i++)
158 enqueue(&queue, A[i]+tid*N);
159 for(int i=0; i<N; i++)
160 dequeue(&queue, &(RESULT[tid][i]));
161}
162
163int main(){
164 for(int i=0; i<N; i++)
165 A[i] = i+1;
166 for(int i=0; i<T; i++)
167 for(int j=0; j<N; j++)
168 RESULT[i][j] = 0;
169 initialize(&queue);
170 $parfor(int i: 0 .. T-1)
171 thread(i);
172 free(queue.Head.ptr);
173}
174
175
176
177
178
Note: See TracBrowser for help on using the repository browser.