8 typedef void* (*read_func_ptr_t)(void*);
12 Every read will read the up-to-date value, and only one thread can be
20 Type *__data_ptr = NULL;
21 bool __is_writing = false;
23 static bool _is_equals(void* ptr1, void* ptr2) {
24 //... Should be defined to check if the internal data equals
36 Fixed the write to be lock-free. Use a CAS in the write instead of using the
37 mutex. There are a couple options for the implementation according to Hans
38 Boehm's paper <<Can seqlocks get along with programming language memory
41 Interesting thing in the read() function is the memory ordering we should
42 impose there. In Hans Boehm's paper, he presents 3 ways to do it. We will
43 try to use the fences one here as a special case to check programs written
47 template<typename Type>
50 // To make the write lock-free, we don't need the mutex here.
51 // Mutex to write exclusively
53 // Sequence for reader consistency check
55 // The shared data structure to be protected;
56 // It needs to be atomic to avoid data races
59 // This function is to check if the objects pointed by the two pointer are
60 // the same; it is only used for checking the correctness
61 bool is_equal(void *ptr1, void *ptr2) {
62 // return ptr1 == NULL ? false : ptr1->equals(ptr2);
69 @Commit_point_set: Init_Point
76 _data.store(data, memory_order_relaxed);
77 _seq.store(0, memory_order_release);
81 @Commit_point_check_define: true
92 @Commit_point_set: Read_Success_Point
95 void *_Old_data_ptr = __data_ptr;
97 _is_equal(read_func(_Old_data_ptr), __RET__)
100 void* read(read_func_ptr_t read_func) {
102 int old_seq = _seq.load(memory_order_acquire);
103 if (old_seq % 2 == 1) continue;
104 // A customized read of something return a pointer to it
105 // Potential data race, should be atomic
106 void *res = read_func(_data.load(memory_order_relaxed));
107 // This is subtle to use an acquire fence here
108 // What we actually need is a #LoadLoad fence
109 atomic_thread_fence(memory_order_acquire);
111 if ((new_seq = _seq.load(memory_order_relaxed)) == old_seq) {
114 @Commit_point_check_define: __ATOMIC_RET__ == old_seq
115 @Label: Read_Success_Point
120 // _data has been updated, read should retry
127 @Commit_point_set: Write_Success_Point
130 __data_ptr = new_data;
134 void write(Type *new_data) {
136 // This might be a relaxed too
137 // Should think about how to read the lo
138 int old_seq = _seq.load(memory_order_acquire);
139 if (old_seq % 2 == 1) {
140 // Backoff, another thread is writing
144 // Should be relaxed!!!
145 if (_seq.compare_exchange_strong(old_seq, old_seq + 1,
146 memory_order_relaxed, memory_order_relaxed))
149 // Should be a store release, to synchronize with the fence!!!
150 _data.store(new_data, memory_order_release);
151 _seq.fetch_add(1, memory_order_release);
154 @Commit_point_define: true
155 @Label: Write_Success_Point