在åŒé‡æ£€æŸ¥é”定模å¼ä¸­èŽ·å–éšœç¢

时间:2015-10-14 02:36:45

标签: c++ multithreading

在C++ and the Perils of Double-Checked Locking中,作者给出了一个如何正确实现模å¼çš„例å­ã€‚

Singleton* Singleton::instance () {
   Singleton* tmp = pInstance;
   ... // insert memory barrier (1)
   if (tmp == 0) {
      Lock lock;
      tmp = pInstance;
      if (tmp == 0) {
         tmp = new Singleton;
         ... // insert memory barrier (2)
         pInstance = tmp;
      }
   }
   return tmp;
}

但是,我无法弄清楚,如果第一个记忆障ç¢å¿…须在Singleton* tmp = pInstance;之åŽï¼Ÿ (编辑:è¦æ¸…楚,我明白需è¦å±éšœã€‚我ä¸æ˜Žç™½çš„是,如果必须在分é…tmp之åŽå‡ºçŽ°ï¼‰å¦‚果是这样,为什么?以下是无效的å—?

Singleton* Singleton::instance () {
   ... // insert memory barrier (1)
   if (pInstance == 0) {
      Lock lock;
      if (pInstance == 0) {
         Singleton* tmp = new Singleton;
         ... // insert memory barrier (2)
         pInstance = tmp;
      }
   }
   return pInstance;
}

2 个答案:

答案 0 :(得分:2)

这是必ä¸å¯å°‘的。å¦åˆ™ï¼Œåœ¨å¤åˆ¶ä¹‹å‰CPUå¯èƒ½ä¼šé¢„å–if之åŽå‘生的读å–,这将是一场ç¾éš¾ã€‚在pInstanceä¸ä¸ºNULL并且我们没有获å–任何é”的情况下,您必须ä¿è¯åœ¨è¯»å–代ç ä¸­çš„pInstance之åŽå‘生的读å–ä¸ä¼šé‡æ–°æŽ’åºåˆ°é˜…读pInstance。

考虑:

Singleton* tmp = pInstance;
if (tmp == 0) { ... }
return tmp->foo;

如果CPU在tmp->foo之å‰è¯»å–tmp会怎样?例如,CPUå¯ä»¥å°†å…¶ä¼˜åŒ–为:

bool loaded = false;
int return_value = 0;

if (pInstance != NULL)
{ // do the fetch early
     return_value = pInstance->foo;
     loaded = true;
}

Singleton* tmp = pInstance;
if (tmp == 0) { ... }

return loaded ? return_value : tmp->foo;

注æ„这是åšä»€ä¹ˆçš„?如果指针是éžNULL,则tmp->foo的读å–现在已移至检查之å‰ã€‚这是CPUå¯èƒ½æ‰§è¡Œçš„完全åˆæ³•çš„内存预å–优化(推测读å–)。但它对åŒé‡æ£€æŸ¥é”定的逻辑ç»å¯¹æ˜¯ç¾éš¾æ€§çš„。

在我们看到if (tmp == 0)为éžNULL之å‰ï¼ŒpInstance之åŽçš„代ç ä¸èƒ½é¢„å–任何内容,这一点至关é‡è¦ã€‚因此,您需è¦ä¸€äº›ä¸œè¥¿æ¥é˜»æ­¢CPUé‡æ–°ç»„织代ç çš„内存æ“作,如上所述。记忆障ç¢å°±æ˜¯è¿™æ ·åšçš„。

答案 1 :(得分:1)

为什么你还在谈论2004年的论文? C ++ 11ä¿è¯é™æ€å˜é‡åªåˆå§‹åŒ–一次。这是你的全é¢å·¥ä½œï¼Œ100%正确的å•èº«äººå£«ï¼ˆå½“然,这是一个å模å¼çš„å•èº«äººå£«ï¼‰ï¼š

static TheTon& TheTon::instance() {
    static TheTon ton;
    return ton;
}