shared_ptr::~shared_ptr() { if (count-- == 1) { deleted ptr; } }
xadd val,(ptr)
void stack::push(const T& data) { node* new_node = new node(data); new_node->next = head; <context switch> head = new_node; }
bool __atomic_compare_exchange (type *ptr, type *pexp, type vnew); void stack::push(const T& data) { node* new_node = new node(data); new_node->next = head; while(!__atomic_compare_exchange( &head, // ptr to value &new_node->next, // ptr to expected value new_node) // new value ) ; }
mov (pexp), %eax ; store expected in %eax cmpxchg vnew, (ptr) ; try store new in ptr sete %cl ; test %cl,%cl ; check cmpxchg status jne _success ; exit on sucess mov %eax, (pexp) ; move updated current value to expected _success:
bool isReady = false; Job* job = nullptr; void prepareJob() { job = new Job(); isReady = true; } void waitForJob() { while (!isReady) std::this_thread::yield(); job->process(); }
0000000000400676 <_Z10prepareJobv>: sub $0x8,%rsp mov $0x1,%edi callq 400570 <_Znwm@plt> movb $0x1,0x2009d5(%rip) # 601060 <isReady> mov %rax,0x2009c6(%rip) # 601058 <job> add $0x8,%rsp retq
0000000000400676 <_Z10prepareJobv>: sub $0x8,%rsp mov $0x1,%edi callq 400570 <_Znwm@plt> mov %rax,0x2009cd(%rip) # 601058 <job> movb $0x1,0x2009ce(%rip) # 601060 <isReady> add $0x8,%rsp retq
// ... void prepareJob() { job = new Job(); asm volatile("" ::: "memory"); isReady = true; } // ...
shared_ptr::~shared_ptr() { if (count-- == 1) { deleted ptr; } }
type __atomic_fetch_add (type *ptr, type val, int memorder) shared_ptr::~shared_ptr() { if (__atomic_fetch_add(&count, -1, __ATOMIC_SEQ_CST) == 0) { deleted ptr; } }
lock xadd val,(ptr)
dmb sy _loop: ldrex r0, [ptr] add r0, val strex r1, r0, [ptr] cmp r1, #0 bne.n _loop dmb sy
sync _loop: lwarx r10,0,ptr add r10,r10,val stwcx. r10,0,ptr mcrf cr7,cr0 bne cr7,_lop isync
void stack::push(const T& data) { node* new_node = new node(data); new_node->next = head; head = new_node; }
bool __atomic_compare_exchange_n (type *ptr, type *pexp, type vnew, bool weak, int success_memorder, int failure_memorder) void stack::push(const T& data) { node* new_node = new node(data); new_node->next = head; while(!__atomic_compare_exchange_n( &head, // ptr to value &new_node->next, // ptr to expected value new_node, // new value false, // weak vs strong __ATOMIC_SEQ_CST, // success memory order __ATOMIC_SEQ_CST) // failure memory order ) ; }
mov (pexp), %eax ; store expected in %eax lock cmpxchg vnew, (ptr) ; try store new in ptr sete %cl ; test %cl,%cl ; check cmpxchg status jne _success ; exit on sucess mov %eax, (pexp) ; move updated current value to expected _success:
ldr vexp, [pexp, #0] ; load the expected value dmb sy ; memory barrier _loop: ldrex rval, [ptr] ; load ptr to rval and make reservation cmp rval, vexp ; check if loaded value equals expected bne.n _exit ; exit otherwise strex r0, vnew, [ptr] ; try to store vnew to ptr cmp.w r0, #0 ; check status bne.n _loop ; loop if lost reservation _exit: dmb sy ; memory barrier ite ne ; movne r1, #0 ; store the result moveq r1, #1 ; cmp r1, #0 ; check status bne.n _success ; exit on success str rval, [pexp, #0] ; move updated current value to expected _success:
sync ; memory barrier _loop: lwarx rval,0,ptr ; load ptr to rval and make reservation cmpw cr7,rval,vexp ; check if loaded value equals expected bne cr7, _exit ; exit otherwise stwcx. vnew,0,ptr ; try to store vnew to ptr mcrf cr7,cr0 ; get the result from conditional register bne cr7, _loop ; loop if lost reservation _exit: isync ; memory barrier mfcr r8 ; get the result from conditional register rlwinm r8,r8,31,31,31 ; cmpwi cr7,r8,0 ; check status bne cr7, _success ; exit on success stw rval,0(pexp) ; move updated current value to expected _success:
bool isReady = false; Job* job = nullptr; void prepareJob() { job = new Job(); isReady = true; } void waitForJob() { while (!isRead) std::this_thread::yield(); job->process(); }
bool isReady = false; Job* job = nullptr; void prepareJob() { job = new Job(); smp_wmb(); isReady = true; } void waitForJob() { while (!isRead) std::this_thread::yield(); job->process(); }
int done1 = 0, done2 = 0, firstOne = -1; int main(int argc, char* argv[]) { std::thread t1([&] { done1 = 1; if (done2) firstOne = 2; }); std::thread t2([&] { done2 = 1; if (done1) firstOne = 1; }); t1.join(); t2.join(); assert(firstOne == 1 || firstOne == 2); }
bool isReady = false; Job* job = nullptr; void prepareJob() { job = new Job(); smp_wmb(); isReady = true; } void waitForJob() { while (!isRead) std::this_thread::yield(); job->process(); }
bool isReady = false; Job* job = nullptr; void prepareJob() { job = new Job(); smp_wmb(); isReady = true; } void waitForJob() { while (!isRead) std::this_thread::yield(); smp_rmb(); job->process(); }
Job* job = firstJob; bool jobConsumed; void consumer() { Job *oldJob = job; jobConsumed = 1; oldJob->process(); } void producer() { if (jobConsumed) { job = nextJob; } }
LOADES reordered afer LOADES |
N | Y | Y | LOADES reordered afer STORES |
N | Y | Y |
---|---|---|---|
STORES reordered afer STORES |
N | Y | Y |
STORES reordered afer LOADES |
Y | Y | Y |
Memory model | STRONG | WEAK | WEAK |
bool isReady = false; Job* job = nullptr; void prepareJob() { job = new Job(); smp_wmb(); isReady = true; } void waitForJob() { while (!isRead) std::this_thread::yield(); smp_rmb(); job->process(); }
std::atomic<int> isReady(0); Job* job = nullptr; void prepareJob() { | Job* tmp = (Job*) malloc(sizeof(Job)); | tmp->field1 = 1; job = new Job(); <-| tmp->field2 = 2; | job = tmp; isReady.store(1, std::memory_order_release); // do some other stuff } void waitForJob() { while (! isReady.load(std::memory_order_acquire)) {}; job->process(); }
Use a spacebar or arrow keys to navigate