source: CIVL/examples/concurrency/two_lock_queue.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: 2.6 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 <civlc.cvh>
9#include <stdbool.h>
10#include <stdlib.h>
11#include <assert.h>
12
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)); // in root scope
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
66void test1() {
67 queue_t queue;
68 int x;
69
70 initialize(&queue);
71 enqueue(&queue, 99);
72 dequeue(&queue, &x);
73 free(queue.Head);
74 assert(x==99);
75}
76
77void test2() {
78 queue_t q;
79 $proc t0, t1;
80 void thread(int val) { enqueue(&q, val); }
81 int x, y;
82 _Bool result;
83
84 initialize(&q);
85 t0 = $spawn thread(6);
86 t1 = $spawn thread(7);
87 $wait(t0);
88 $wait(t1);
89 result = dequeue(&q, &x);
90 assert(result);
91 result = dequeue(&q, &y);
92 assert(result);
93 assert ((x==6 && y==7) || (x==7 && y==6));
94 free(q.Head);
95}
96
97void main() {
98 test2();
99}
Note: See TracBrowser for help on using the repository browser.