Subj : Re: CMPXCHG timing To : comp.programming.threads From : Michael Pryhodko Date : Thu Mar 31 2005 09:27 pm Very strange... I've tried to test implementation of the idea above and it fails to reasons I do not understand! Here is the sources of testing application. Somehow I could get to the "we should not be here line" on my P4 2.8GHz HT -- which is totally confusing to me, only current thread ever writes this specific unique id into m_lock variable and since we are at the beginning of lock() -- m_lock should be != curr_thread_id. It look like I am blind. ----------------------------------- sources ----------------------------------- #include #include #include #include #define THREAD_COUNT (5) ////////////////////////////////////////////////// // mtlock class class mtlock { __declspec(align(32)) LONG m_lock; public: mtlock() throw() : m_lock(0) {} ~mtlock() throw() {} void lock(LONG dwId) throw() { LONG dummy = 5; if (m_lock == dwId) { // !! we should not be here! But it just happens :( !! __asm { int 3 } } __asm { mov edx, dwId mov ebx, this mfence ENTER_LOCK: // CAS(&m_lock, 0, dwId) xor eax, eax mov ecx, edx cmpxchg [ebx]this.m_lock, ecx sfence // if (successfull) je PROCEED pause jmp ENTER_LOCK PROCEED: // CAS(&dummy, dummy, ~dummy) mov ecx, dummy mov eax, ecx neg ecx cmpxchg dummy, ecx mfence // if (m_lock == dwId) cmp [ebx]this.m_lock, edx je EXIT_LOCK pause jmp ENTER_LOCK EXIT_LOCK: } } void unlock(LONG dwId) throw() { if (m_lock != dwId) { __asm { int 3 } } __asm { mov eax, this mov [eax]this.m_lock, 0 sfence } } }; ////////////////////////////////////////////////// // global variables mtlock lock; LONG g_stat[THREAD_COUNT] = {0}; // enter/leave stats #define ASSERT(x) if (!(x)) { __asm { int 3 }; } void __cdecl thread_proc(void* pData) { LONG dwThreadId = GetCurrentThreadId(); LONG idx = (LONG)pData; for(;;) { lock.lock(dwThreadId); ++g_stat[idx]; lock.unlock(dwThreadId); Sleep(0); } } int _tmain(int argc, _TCHAR* argv[]) { for(int i = 0; i < THREAD_COUNT; ++i) { _beginthread(&thread_proc, 0, (void*)i); } Sleep(10000); lock.lock(GetCurrentThreadId()); for(int i = 0; i < THREAD_COUNT; ++i) { std::cout << i << " " << g_stat[i] << std::endl; } lock.unlock(GetCurrentThreadId()); return 0; } .