MCS锁实现中的死锁

问题描述 投票:1回答:1
硬件:达尔文内核版本13.2.0:PDT 2014年4月17日23:03:13;根目录:xnu-2422.100.13〜1 / RELEASE_X86_64 x86_64
atomics.hpp1 #ifndef ATOMIC_UTILS_H2#定义ATOMIC_UTILS_H34#包括56 #define BARRIER()__asm__ volatile(“”:::“内存”)78#定义CPU_RELAX()__asm__ volatile(“ pause \ n \ t”:::“ memory”)910#定义STORE_FENCE()__asm__ volatile(“ mfence” :::“内存”);1112类AtomicUtils13 {14个公众:1516 / **17 *检查addr的值是否等于oldval,如果是,则将其替换为newva l18 *并返回旧版本19 * /20个内联静态size_t compareAndExchange(volatile size_t * addr,size_t oldval,size_t newval)21 {22 size_t ret;23 __asm__ volatile(“锁定cmpxchgq%2,%1 \ n \ t”24:“ = a”(ret),“ + m”(* addr)25:“ r”(新值),“ 0”(旧值)26:“存储器”);27返回ret;28}2930 / **31 *以原子方式将x存储到addr中并返回前一个32 *存储在地址中33 * /34个内联静态size_t loadAndStore(size_t x,volatile size_t * addr)36 {37 size_t ret;38 __asm__ volatile(“锁定xchgq%1,%0 \ n \ t”39:“ + m”(* addr),“ = r”(ret)40:“ 1”(x));41返回ret;42}4344};4546 #endif
mcs.hpp1 #ifndef MCS_LOCK_H2#定义MCS_LOCK_H34 #include“ atomics.hpp”5#包括67级MCSLock8 {9结构mcs_lock_t10 {11 mcs_lock_t():下一个(0),已锁定(false){}12 struct mcs_lock_t *接下来;13布尔锁定;14};1516个公众:17 typedef struct mcs_lock_t mcs_lock;18岁19个私有:20 mcs_lock **尾巴;21静态boost :: thread_specific_ptr tls_node;2223个公众:24 MCSLock(mcs_lock ** lock_tail):tail(锁尾)25 {26 if(tls_node.get()== 0)27 tls_node.reset(new mcs_lock());28}2930 void lock()31 {32 mcs_lock * thread_node = tls_node.get();33 thread_node-> next = 0;34 thread_node-> locked = true;3536 volatile mcs_lock * pred = reinterpret_cast(37 AtomicUtils :: loadAndStore(38 reinterpret_cast(thread_node),39 reinterpret_cast(tail)40)41);42 if(pred!= 0)43 {44 pred-> next = * tail;4546 STORE_FENCE();第47章//为防止在prev-> next = tail和thread_node-> locked之间重新排序而需要。 (WR harzard)4849 //旋转局部变量。有人解锁我!50 while(thread_node-> locked)51 CPU_RELAX();5253}54}5556无效unlock()57 {58。59 if(thread_node-> next == 0)60 {61 //如果为false,则我们有一个新线程请求锁定。现在释放锁定新线程62如果(63 AtomicUtils :: compareAndExchange(64 reinterpret_cast(tail),65 reinterpret_cast(thread_node),66 067)== reinterpret_cast(thread_node)68)69 {70回报;71}7273 while(thread_node-> next == 0)74 CPU_RELAX();75}7677 thread_node-> next-> locked = false;78}79};8081 boost :: thread_specific_ptr MCSLock :: tls_node;82 #endif
mcs_test.cpp

  1 #include "mcs.hpp"
  2 #include <iostream>
  3 #include <pthread.h>
  4 #include <vector>
  5 #define NUM_THREADS 16
  6 #define NUM_ITERATIONS 100
  7
  8 std::vector<int> elements;
  9 MCSLock::mcs_lock *tail = 0;
 10
 11 void* thread_run( void* data )
 12 {
 13   MCSLock lock( &tail );
 14   for( int i = 0; i < NUM_ITERATIONS; ++i )
 15   {
 16       lock.lock();
 17       elements.push_back( i );
 18       lock.unlock();
 19   }
 20
 21   return 0;
 22 }
 23
 24 int main()
 25 {
 26     pthread_t threads[ NUM_THREADS ];
 27     elements.reserve( NUM_THREADS * NUM_ITERATIONS );
 28
 29     {
 30         for( int i = 0; i < NUM_THREADS; ++i )
 31             pthread_create( &threads[i], NULL, thread_run, NULL );
 32
 33         for( int i = 0; i < NUM_THREADS; ++i )
 34             pthread_join( threads[i], NULL );
 35
 36         std::cout <<"\nExiting main thread: " << std::endl;
 37     }
 38 }

以上代码使用clang编译

问题:

我看到第50行的1(或2)个线程被卡在lock()中。除了主线程之外,被锁在lock()中的线程没有其他活动线程。这意味着,当其他线程调用unlock()时,它们就不以其他方式将其他变量设置为locked = false并退出。

是否有调试提示?

坚持了好几个小时,一无所获。

multithreading locking x86-64 atomic inline-assembly
1个回答
1
投票

clang是否没有为这些内联asm块(例如gcc的__sync_val_compare_and_swap)内置函数?为什么要重新发明轮子?

其次,我真的想过将内存破坏者添加到loadAndStore。在执行xchgq之前,您需要确保编译器保存在寄存器中的所有写操作都被刷新到内存中。同样,它将防止gcc将内存读取优化到xchgq之前。两者都会不好。

[第三,我将检查while循环(线程节点锁定的线程和线程节点下一步的线程)的asm输出。由于这些变量不是易变的,因此gcc可能会将其优化为仅执行一次读取。]

这些可能无法解决您的问题,但这就是我要开始的地方。

© www.soinside.com 2019 - 2024. All rights reserved.