source: CIVL/examples/compare/queue/queue_non_blocking.c@ d04e4b0

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

added two-lock queue and non-blocking queue implementation

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

  • Property mode set to 100644
File size: 3.0 KB
Line 
1#ifndef _QUEUE_NON_BLOCKING_
2#define _QUEUE_NON_BLOCKING_
3
4#include <stdbool.h>
5#include <stdlib.h>
6#include "queue.h"
7
8typedef struct pointer_t pointer_t;
9
10typedef struct node_t {
11 int value;
12 pointer_t next;
13} node_t;
14
15struct pointer_t {
16 node_t* ptr;
17 int count;
18};
19
20struct queue_t {
21 pointer_t Head;
22 pointer_t Tail;
23};
24
25_Bool eq(pointer_t p1, pointer_t p2){
26 return p1.ptr == p2.ptr && p1.count == p2.count;
27}
28
29_Bool neq(pointer_t p1, pointer_t p2){
30 return p1.ptr != p2.ptr || p1.count != p2.count;
31}
32
33_Bool CAS(pointer_t *p, pointer_t old, pointer_t new){
34 $atomic{
35 if(neq(*p, old))
36 return false;
37 *p = new;
38 return true;
39 }
40}
41
42void initialize(queue_t *Q){
43 node_t *node=(node_t*)malloc(sizeof(node_t)); // Allocate a free node
44
45 node->next.ptr = NULL; // Make it the only node in the linked list
46 node->next.count = 0;
47 Q->Head.ptr = Q->Tail.ptr = node; // Both Head and Tail point to it
48}
49
50void enqueue(queue_t *Q, int value){
51 node_t *node = (node_t*) malloc(sizeof(node_t)); // Allocate a new node from the free list
52 pointer_t tail, next;
53
54 node->value = value; // Copy enqueued value into node
55 node->next.ptr = NULL; // Set next pointer of node to NULL
56 while(true){ // Keep trying until Enqueue is done
57 tail = Q->Tail; // Read Tail.ptr and Tail.count together
58 next = tail.ptr->next; // Read next ptr and count fields together
59 if(eq(tail, Q->Tail)) // Are tail and next consistent?
60 // Was Tail pointing to the last node?
61 if(next.ptr == NULL){
62 // Try to link node at the end of the linked list
63 if(CAS(&tail.ptr->next, next, (pointer_t){node, next.count+1}));
64 break; // Enqueue is done. Exit loop
65 }else{ // Tail was not pointing to the last node
66 // Try to swing Tail to the next node
67 CAS(&Q->Tail, tail, (pointer_t){next.ptr, tail.count+1});
68 }
69 }
70 // Enqueue is done. Try to swing Tail to the inserted node
71 CAS(&Q->Tail, tail, (pointer_t){node, tail.count+1});
72}
73
74_Bool dequeue(queue_t *Q, int *pvalue){
75 pointer_t head, tail, next;
76
77 while(true){ // Keep trying until Dequeue is done
78 head = Q->Head; // Read Head
79 tail = Q->Tail; // Read Tail
80 next = head.ptr->next; // Read Head.ptr->next
81 if(eq(head, Q->Head)) // Are head, tail, and next consistent?
82 if(head.ptr == tail.ptr){ // Is queue empty or Tail falling behind?
83 if(next.ptr == NULL) // Is queue empty?
84 return false; // Queue is empty, couldn't dequeue
85 // Tail is falling behind. Try to advance it
86 CAS(&Q->Tail, tail, (pointer_t){next.ptr, tail.count+1});
87 } else{ // No need to deal with Tail
88 // Read value before CAS
89 // Otherwise, another dequeue might free the next node
90 *pvalue = next.ptr->value;
91 // Try to swing Head to the next node
92 if(CAS(&Q->Head, head, (pointer_t){next.ptr, head.count+1}));
93 break; // Dequeue is done. Exit loop
94 }
95 }
96 free(head.ptr); // It is safe now to free the old node
97 return true; // Queue was not empty, dequeue succeeded
98}
99
100void freequeue(queue_t q){
101 free(q.Tail.ptr);
102}
103
104#endif
Note: See TracBrowser for help on using the repository browser.