--- /dev/null
+Inference results for this benchmark are consistent with the manual analysis.
+In the write() function, either the load of _seq at the very beginning or the CAS
+of the _seq when it succeeds must be acquire such that it establishes
+synchronization between two contiguous write(). If not, the two _data.store
+operations are not ordered by hb, and the next read() can read either, thus
+allowing reading the wrong (old) value.
}
void write(int new_data) {
- int old_seq = _seq.load(wildcard(4)); // acquire
while (true) {
+ int old_seq = _seq.load(wildcard(4)); // acquire
if (old_seq % 2 == 1)
continue; // Retry
// Should be relaxed!!!
if (_seq.compare_exchange_strong(old_seq, old_seq + 1,
- wildcard(5), wildcard(6))) // relaxed
+ wildcard(5), wildcard(6))) // relaxed
break;
}
#include <stdatomic.h>
#include <threads.h>
+#include "common.h"
typedef struct seqlock {
// Sequence for reader consistency check
}
void write(int new_data) {
- int old_seq = _seq.load(memory_order_acquire); // acquire
while (true) {
+ // #1: either here or #2 must be acquire
+ int old_seq = _seq.load(memory_order_acquire); // acquire
// This might be a relaxed too
if (old_seq % 2 == 1)
continue; // Retry
+ // #2
if (_seq.compare_exchange_strong(old_seq, old_seq + 1,
- memory_order_acq_rel, memory_order_acquire))
+ memory_order_relaxed, memory_order_relaxed))
break;
}
static void b(void *obj) {
lock->write(2);
+ int r1 = lock->read();
}
static void c(void *obj) {
- lock->write(2);
int r1 = lock->read();
}
lock = new seqlock_t();
thrd_create(&t1, (thrd_start_t)&a, NULL);
- //thrd_create(&t2, (thrd_start_t)&b, NULL);
- thrd_create(&t3, (thrd_start_t)&c, NULL);
+ thrd_create(&t2, (thrd_start_t)&b, NULL);
+ //thrd_create(&t3, (thrd_start_t)&c, NULL);
thrd_join(t1);
- //thrd_join(t2);
- thrd_join(t3);
+ thrd_join(t2);
+ //thrd_join(t3);
return 0;
}