Repository navigation
Expand file tree
/
Copy pathexample.c
More file actions
140 lines (116 loc) · 4.59 KB
/
Copy pathexample.c
File metadata and controls
140 lines (116 loc) · 4.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <threads.h>
#include "faaq.h"
// Configuration for the multi-threaded example
#define NUM_PRODUCERS 2
#define NUM_CONSUMERS 2
#define TOTAL_THREADS (NUM_PRODUCERS + NUM_CONSUMERS)
#define ITEMS_PER_PRODUCER 10000
// Shared queue for the multi-threaded example
FAAArrayQueue_t *g_queue = NULL;
_Atomic uint64_t g_dequeued_count = 0;
// --- Single-Threaded Example ---
void
run_simple_example() {
printf("--- Running Simple Single-Threaded Example ---\n");
// Create a queue. Nothing about the threads that will use it needs to be
// declared up front: each thread attaches itself on first use.
FAAArrayQueue_t *q = faa_queue_create();
assert(q != NULL);
printf("Queue created successfully.\n");
// Enqueue some items.
// For this simple example, we cast integers to void pointers.
printf("Enqueuing items: 10, 20, 30\n");
faa_queue_enqueue(q, (void *) 10);
faa_queue_enqueue(q, (void *) 20);
faa_queue_enqueue(q, (void *) 30);
// Dequeue items and verify FIFO order.
void *item1 = faa_queue_dequeue(q);
void *item2 = faa_queue_dequeue(q);
void *item3 = faa_queue_dequeue(q);
void *empty_item = faa_queue_dequeue(q);
printf("Dequeued items: %ld, %ld, %ld\n", (intptr_t) item1, (intptr_t) item2, (intptr_t) item3);
assert((intptr_t) item1 == 10);
assert((intptr_t) item2 == 20);
assert((intptr_t) item3 == 30);
assert(empty_item == NULL); // Dequeue from an empty queue returns NULL
printf("FIFO order verified. Dequeue on empty queue works.\n");
// Destroy the queue to free all memory.
// This should only be done when you are sure no other threads are
// accessing the queue (e.g., after all threads are joined).
faa_queue_destroy(q, nullptr);
printf("Queue destroyed successfully.\n\n");
}
// --- Multi-Threaded Example ---
int
producer_thread(void *arg) {
int id = (int) (intptr_t) arg;
printf("Producer thread %d started.\n", id);
for (int i = 0; i < ITEMS_PER_PRODUCER; ++i) {
// In a real application, you would allocate memory for your data.
// We'll enqueue the item's number, ensuring it's not NULL.
intptr_t value = (intptr_t) (i + 1);
faa_queue_enqueue(g_queue, (void *) value);
}
printf("Producer thread %d finished.\n", id);
return 0;
}
int
consumer_thread(void *arg) {
int id = (int) (intptr_t) arg;
printf("Consumer thread %d started.\n", id);
while (atomic_load(&g_dequeued_count) < (NUM_PRODUCERS * ITEMS_PER_PRODUCER)) {
void *item = faa_queue_dequeue(g_queue);
if (item != NULL) {
// In a real application, you would process the item here.
// If the item was dynamically allocated, you would free it.
atomic_fetch_add(&g_dequeued_count, 1);
} else {
// Yield if the queue is temporarily empty to avoid busy-waiting.
thrd_yield();
}
}
printf("Consumer thread %d finished.\n", id);
return 0;
}
void
run_multithread_example() {
printf("--- Running Multi-Threaded Example ---\n");
printf("%d Producers, %d Consumers, %d Items per Producer\n", NUM_PRODUCERS, NUM_CONSUMERS, ITEMS_PER_PRODUCER);
// Any number of threads may use the queue; no ids, no registration.
g_queue = faa_queue_create();
assert(g_queue != NULL);
thrd_t threads[TOTAL_THREADS];
// Create and start producer and consumer threads.
for (int i = 0; i < NUM_PRODUCERS; ++i) {
thrd_create(&threads[i], producer_thread, (void *) (intptr_t) i);
}
for (int i = 0; i < NUM_CONSUMERS; ++i) {
thrd_create(&threads[NUM_PRODUCERS + i], consumer_thread, (void *) (intptr_t) i);
}
// Wait for all threads to complete.
for (int i = 0; i < TOTAL_THREADS; ++i) {
thrd_join(threads[i], NULL);
}
printf("All threads have finished.\n");
// Verification
uint64_t total_dequeued = atomic_load(&g_dequeued_count);
uint64_t total_expected = NUM_PRODUCERS * ITEMS_PER_PRODUCER;
printf("Total items dequeued: %llu\n", (unsigned long long) total_dequeued);
printf("Total items expected: %llu\n", (unsigned long long) total_expected);
assert(total_dequeued == total_expected);
assert(faa_queue_dequeue(g_queue) == NULL); // Queue should be empty now
printf("Verification successful.\n");
// Destroy the queue.
faa_queue_destroy(g_queue, nullptr);
printf("Queue destroyed successfully.\n");
}
int
main() {
run_simple_example();
run_multithread_example();
return 0;
}