165869e8 |
1 | #include "queue.h" |
2 | #include <stdlib.h> |
3 | #include <pthread.h> |
4 | |
5 | /* Requirements 4 & 5 for Homework 09 indicate that you should modify the add |
6 | * and pop methods for the queue to provide for thread safety. If you modify |
7 | * the producer and consumer methods instead you will not receive full credit |
8 | * for the solution. Additionally, the due date for the homework is now |
9 | * Thursday to provide for the necessary modifications to fulfill requirements |
10 | * 4 & 5. Please note that you should NOT be using a global mutex. Any |
11 | * structures you use to protect the queue should be associated with the |
12 | * particular queue that is being used (the one given to the add/pop methods). |
13 | * */ |
14 | |
15 | /* private methods */ |
16 | |
17 | static void clear_node(queue_node_t* node) |
18 | { |
19 | if (node != NULL) |
20 | { |
21 | clear_node(node->next); |
22 | free(node); |
23 | } |
24 | } |
25 | |
26 | static queue_node_t* create_node(int value) |
27 | { |
28 | queue_node_t* node = malloc(sizeof(queue_node_t)); |
29 | node->value = value; |
30 | node->next = NULL; |
31 | return node; |
32 | } |
33 | |
34 | /* public methods */ |
35 | |
36 | void queue_init(queue_t* queue) |
37 | { |
38 | queue->root = NULL; |
39 | |
40 | queue->mx_pop = (pthread_mutex_t *) calloc(1, sizeof(pthread_mutex_t)); |
41 | queue->mx_push = (pthread_mutex_t *) calloc(1, sizeof(pthread_mutex_t)); |
42 | queue->mx_valid_root = (pthread_mutex_t *) calloc(1, sizeof(pthread_mutex_t)); |
43 | queue->valid_root = (pthread_cond_t *) calloc(1, sizeof(pthread_cond_t)); |
44 | |
45 | pthread_mutex_init(queue->mx_pop, NULL); |
46 | pthread_mutex_init(queue->mx_push, NULL); |
47 | pthread_mutex_init(queue->mx_valid_root, NULL); |
48 | |
49 | pthread_cond_init(queue->valid_root, NULL); |
50 | |
51 | return; |
52 | } |
53 | |
54 | void queue_clear(queue_t* queue) |
55 | { |
56 | clear_node(queue->root); |
57 | free(queue->mx_pop); |
58 | free(queue->mx_push); |
59 | free(queue->valid_root); |
60 | return; |
61 | } |
62 | |
63 | /* edit */ |
64 | void queue_add(queue_t* queue, int value) |
65 | { |
66 | pthread_mutex_lock(queue->mx_push); |
67 | pthread_mutex_lock(queue->mx_valid_root); |
68 | |
69 | if (queue->root == NULL) |
70 | { |
71 | queue->root = create_node(value); |
72 | pthread_cond_signal(queue->valid_root); |
73 | pthread_mutex_unlock(queue->mx_valid_root); |
74 | } |
75 | else |
76 | { |
77 | pthread_cond_signal(queue->valid_root); |
78 | pthread_mutex_unlock(queue->mx_valid_root); |
79 | |
80 | queue_node_t* last = queue->root; |
81 | while (last->next != NULL) |
82 | { |
83 | last = last->next; |
84 | } |
85 | last->next = create_node(value); |
86 | } |
87 | pthread_mutex_unlock(queue->mx_push); |
88 | return; |
89 | } |
90 | |
91 | /* edit */ |
92 | int queue_pop(queue_t* queue) |
93 | { |
94 | if(queue->root == NULL) { |
95 | |
96 | pthread_mutex_lock(queue->mx_valid_root); |
97 | pthread_cond_wait(queue->valid_root, queue->mx_valid_root); |
98 | pthread_mutex_unlock(queue->mx_valid_root); |
99 | } |
100 | pthread_mutex_lock(queue->mx_pop); |
101 | queue_node_t* temp = queue->root->next; |
102 | int value = queue->root->value; |
103 | free(queue->root); |
104 | queue->root = temp; |
105 | pthread_mutex_unlock(queue->mx_pop); |
106 | return value; |
107 | } |