source: CIVL/examples/experimental/twoLock_final.cvl

main
Last change on this file was ea777aa, checked in by Alex Wilton <awilton@…>, 3 years ago

Moved examples, include, build_default.properties, common.xml, and README out from dev.civl.com into the root of the repo.

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

  • Property mode set to 100644
File size: 4.5 KB
Line 
1/* two_lock_queue.cvl: a "Two-Lock Concurrent
2 * Queue Algorithm", from Michael and Scott,
3 * https://www.cs.rochester.edu/research/synchronization/pseudocode/queues.html.
4 * Originally from "Simple, Fast, and
5 * Practical Non-Blocking and Blocking
6 * Concurrent Queue Algorithms", PODC96.
7 */
8#include <stdio.h>
9#include <civlc.cvh>
10#include <stdbool.h>
11#include <stdlib.h>
12#include <assert.h>
13typedef int lock_t;
14#define FREE 0
15#define lock(l) $when (l==0) l=1;
16#define unlock(l) l=0;
17
18typedef struct node_t {
19 int value;
20 struct node_t *next;
21} node_t;
22
23typedef struct queue_t {
24 node_t *Head;
25 node_t *Tail;
26 lock_t H_lock;
27 lock_t T_lock;
28} queue_t;
29
30void initialize(queue_t *Q) {
31 node_t *node = (node_t*)malloc(sizeof(node_t));
32
33 node->next = NULL; // Make it the only node in the linked list
34 Q->Head = Q->Tail = node; // Both Head and Tail point to it
35 Q->H_lock = Q->T_lock = FREE; // Locks are initially free
36}
37
38void enqueue(queue_t *Q, int value) {
39 node_t *node = (node_t*)malloc(sizeof(node_t));
40
41 node->value = value; // Copy enqueued value into node
42 node->next = NULL; // Set next pointer of node to NULL
43 lock(Q->T_lock); // Acquire T_lock in order to access Tail
44 Q->Tail->next = node; // Link node at the end of the linked list
45 Q->Tail = node; // Swing Tail to node
46 unlock(Q->T_lock); // Release T_lock
47}
48
49_Bool dequeue(queue_t *Q, int *pvalue) {
50 node_t *node, *new_head;
51
52 lock(Q->H_lock); // Acquire H_lock in order to access Head
53 node = Q->Head; // Read Head
54 new_head = node->next; // Read next pointer
55 if (new_head == NULL) { // Is queue empty?
56 unlock(Q->H_lock); // Release H_lock before return
57 return false; // Queue was empty
58 }
59 *pvalue = new_head->value; // Queue not empty. Read value before release
60 Q->Head = new_head; // Swing Head to next node
61 unlock(Q->H_lock); // Release H_lock
62 free(node); // Free node
63 return true; // Queue was not empty, dequeue succeeded
64}
65
66/*****************************************************/
67/******************** Tests **************************/
68/*****************************************************/
69
70/* Determines whether an array of n integers is
71 * a permutation of the numbers 0..n-1. */
72_Bool is_permutation(int n, int *data) {
73 _Bool seen[n];
74
75 for (int i=0; i<n; i++)
76 seen[i] = 0;
77 for (int i=0; i<n; i++) {
78 int value = data[i];
79
80 if (value < 0 || value >= n)
81 return 0;
82 if (seen[value])
83 return 0;
84 seen[value] = 1;
85 }
86 return 1;
87}
88
89void test1() {
90 int d;
91 queue_t sq;
92
93 initialize(&sq);
94 for (int i = 0; i < 10; i++) {
95 enqueue(&sq, i);
96 }
97 for (int i = 0; i < 10; i++) {
98 _Bool result = dequeue(&sq, &d);
99
100 assert(result);
101 assert(d == i);
102 }
103 free(sq.Head);
104}
105
106void test2(int n) { //Test whether dequeued array is a permutation
107 queue_t sq;
108 int array[n];
109
110 initialize(&sq);
111 $parfor(int i: 0 .. (n-1)) {
112 enqueue(&sq, i);
113 dequeue(&sq, &array[i]);
114 }
115 assert(is_permutation(n, array));
116 free(sq.Head);
117}
118
119void test3(int t, int n) { //t is the number of threads,
120 int RESULT[t*n]; //n is the number of enqueued values
121 int R[t][n]; //global array to store scaned result
122 int counter[t]; //global array, each thread has a counter;
123 queue_t sq;
124
125 void thread(int tid){
126 for(int i=0; i<n; i++) {
127 enqueue(&sq, i+1+tid*n);
128 }
129 }
130 void scan(int x){ // helper method for assertFIFO()
131 int tid = 0; // thread id
132
133 tid = (x-1)/n; //calculate the id of thread;
134 R[tid][counter[tid]++] = x; //store scaned elements
135 }
136 void assertFIFO(int *data) { // assert method for testing FIFO
137 for(int i=0; i<t*n; i++)
138 scan(data[i]); //scan dequeued RESULT[t*n];
139 for(int i=0; i<t; i++) //assert FIFO for each thread
140 for(int j=0; j<n-1; j++)
141 assert(R[i][j] < R[i][j+1]);
142 }
143 for(int i=0; i<t; i++) //initialize global R[t][n]
144 for(int j=0; j<n; j++)
145 R[i][j] = 0;
146 for(int i=0; i<t;i++) ///initialize global counter[t]
147 counter[i] = 0;
148 for(int i=0; i<t*n; i++)
149 RESULT[i] = 0;
150
151 initialize(&sq);
152 $parfor(int i: 0 .. t-1)
153 thread(i);
154 for(int i=0; i<t*n; i++)
155 dequeue(&sq, &RESULT[i]);
156 for(int i=0; i<t*n; i++){ //print dequeued result
157 if(i%(t*n)==0)
158 printf("dequeue: ");
159 printf("%d\t", RESULT[i]);
160 }
161 printf("\n");
162 assertFIFO(RESULT);
163 free(sq.Head);
164}
165
166void main() {
167 test1();
168 test2(3);
169 test3(2, 2);
170}
Note: See TracBrowser for help on using the repository browser.