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
141
142
143
144
145
146
147
148
149
150
151
152
|
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <stdatomic.h>
#define NR_THREADS 16
#define NR_STEPS ((uint32_t)UINT16_MAX)
#define BUG_ON(COND) \
do { \
if (!!(COND)) \
abort(); \
} while (0)
#if defined __x86_64__ || defined __aarch64__ || defined __riscv
#define HAS_64BITS
#endif
typedef struct {
atomic_flag flag;
atomic_uchar uc;
atomic_ushort us;
atomic_uint ui;
#ifdef HAS_64BITS
atomic_size_t ul;
#endif
} counter_type;
static
void *adder_simple(void *arg)
{
size_t step;
counter_type *counter = arg;
for (step = 0; step < NR_STEPS; ++step) {
atomic_fetch_add_explicit(&counter->uc, 1, memory_order_relaxed);
atomic_fetch_add_explicit(&counter->us, 1, memory_order_relaxed);
atomic_fetch_add_explicit(&counter->ui, 1, memory_order_relaxed);
#ifdef HAS_64BITS
atomic_fetch_add_explicit(&counter->ul, 1, memory_order_relaxed);
#endif
}
return NULL;
}
static
void *adder_cmpxchg(void *arg)
{
size_t step;
counter_type *counter = arg;
for (step = 0; step < NR_STEPS; ++step) {
unsigned char xchgc;
unsigned short xchgs;
unsigned int xchgi;
#ifdef HAS_64BITS
size_t xchgl;
#endif
unsigned char cmpc = atomic_load_explicit(&counter->uc, memory_order_relaxed);
unsigned short cmps = atomic_load_explicit(&counter->us, memory_order_relaxed);
unsigned int cmpi = atomic_load_explicit(&counter->ui, memory_order_relaxed);
#ifdef HAS_64BITS
size_t cmpl = atomic_load_explicit(&counter->ul, memory_order_relaxed);
#endif
do {
xchgc = (cmpc + 1);
} while (!atomic_compare_exchange_strong_explicit(&counter->uc,
&cmpc, xchgc, memory_order_relaxed, memory_order_relaxed));
do {
xchgs = (cmps + 1);
} while (!atomic_compare_exchange_strong_explicit(&counter->us,
&cmps, xchgs, memory_order_relaxed, memory_order_relaxed));
do {
xchgi = (cmpi + 1);
} while (!atomic_compare_exchange_strong_explicit(&counter->ui,
&cmpi, xchgi, memory_order_relaxed, memory_order_relaxed));
#ifdef HAS_64BITS
do {
xchgl = (cmpl + 1);
} while (!atomic_compare_exchange_strong_explicit(&counter->ul,
&cmpl, xchgl, memory_order_relaxed, memory_order_relaxed));
#endif
}
return NULL;
}
static
void *adder_test_and_set(void *arg)
{
size_t step;
counter_type *counter = arg;
for (step = 0; step < NR_STEPS; ++step) {
while (atomic_flag_test_and_set(&counter->flag));
++counter->uc;
++counter->us;
++counter->ui;
#ifdef HAS_64BITS
++counter->ul;
#endif
atomic_flag_clear(&counter->flag);
}
return NULL;
}
static
void atomic_counter_test(void *(*adder)(void *arg))
{
size_t index;
counter_type counter;
pthread_t thread[NR_THREADS];
atomic_flag_clear(&counter.flag);
atomic_init(&counter.uc, 0);
atomic_init(&counter.us, 0);
atomic_init(&counter.ui, 0);
#ifdef HAS_64BITS
atomic_init(&counter.ul, 0);
#endif
for (index = 0; index < NR_THREADS; ++index)
BUG_ON(pthread_create(&thread[index], NULL, adder, (void *)&counter));
for (index = 0; index < NR_THREADS; ++index)
BUG_ON(pthread_join(thread[index], NULL));
if (atomic_load(&counter.uc) == ((NR_THREADS * NR_STEPS) & 0xffu)
&& atomic_load(&counter.us) == ((NR_THREADS * NR_STEPS) & 0xffffu)
&& atomic_load(&counter.ui) == (NR_THREADS * NR_STEPS)
#ifdef HAS_64BITS
&& atomic_load(&counter.ul) == (NR_THREADS * NR_STEPS)
#endif
)
printf("SUCCESS\n");
else
printf("FAILURE\n");
}
int main(void)
{
atomic_counter_test(adder_simple);
atomic_counter_test(adder_cmpxchg);
atomic_counter_test(adder_test_and_set);
return 0;
}
|