source: CIVL/examples/compare/queue/NonBlockingQueue.cvl@ 859c407

1.23 2.0 main test-branch
Last change on this file since 859c407 was 6a8da77, checked in by Si Li <sili@…>, 11 years ago

Implementation of Non-BlockingQueue.cvl

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

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