Обеспечение использования инструкции double-compare-and-swap для стека блокировки?

(Предположим, что 64-битная архитектура x86-64 и процессор Intel 3/4-го поколения)

Вот реализация блокировки для стека из Concurrency в книге действий, стр. 202:

template<typename T>
class lock_free_stack
{
private:
    struct node;

    struct counted_node_ptr
    {
        int external_count;
        node* ptr;
    };

    struct node
    {
        std::shared_ptr<T> data;
        std::atomic<int> internal_count;
        counted_node_ptr next;

        node(T const& data_):data(std::make_shared<T>(data_)),internal_count(0){}
    };

    std::atomic<counted_node_ptr> head;

public:
    ~lock_free_stack()
    {
        while(pop());
    }

    void push(T const& data)
    {
        counted_node_ptr new_node;
        new_node.ptr=new node(data);
        new_node.external_count=1;
        new_node.ptr->next=head.load();
        while(!head.compare_exchange_weak(new_node.ptr->next,new_node));
    }
};

Он говорит ниже код:

На тех платформах, которые поддерживают двойное слово-сравнение и обмен эта структура будет достаточно мала для std:: atomic для блокировки.

Я считаю, что x86-64 имеет поддержку двойного CAS (я не могу вспомнить название инструкции с верхней части головы).

Если бы я должен был проверить сборку (и я не мог видеть двойную инструкцию CAS), какая встроенная функция сборки мне понадобится для записи, чтобы использовать двойную CAS?

UPDATE - Я думаю, что нашел то, что искал здесь:

http://blog.lse.epita.fr/articles/42-implementing-generic-double-word-compare-and-swap-.html

template<typename T>
struct DPointer <T,sizeof (uint64_t)> {
public:
  union {
    uint64_t ui[2];
    struct {
      T* ptr;
      size_t count;
    } __attribute__ (( __aligned__( 16 ) ));
  };

  DPointer() : ptr(NULL), count(0) {}
  DPointer(T* p) : ptr(p), count(0) {}
  DPointer(T* p, size_t c) : ptr(p), count(c) {}

  bool cas(DPointer<T,8> const& nval, DPointer<T,8> const& cmp)
  {
    bool result;
    __asm__ __volatile__ (
        "lock cmpxchg16b %1\n\t"
        "setz %0\n"
        : "=q" ( result )
         ,"+m" ( ui )
        : "a" ( cmp.ptr ), "d" ( cmp.count )
         ,"b" ( nval.ptr ), "c" ( nval.count )
        : "cc"
    );
    return result;
  }

  // We need == to work properly
  bool operator==(DPointer<T,8> const&x)
  {
    return x.ptr == ptr && x.count == count;
  }
};

Ответ 1

Самые старые версии x86_64 не поддерживают эту инструкцию (CMPXCHG16B), которая требуется для Windows 8.1/64-бит и новее. Afaik это большая часть диапазона Athlon64 (сокет 751, 939 и некоторые из X2, возможно, и первое поколение (8xx) Pentium D)

Как заставить компилятор использовать определенную команду, меняется, как правило, нужно использовать не полностью переносимую внутреннюю.

Ответ 2

Вы можете утверждать

std::atomic<T>::is_lock_free()