2014-09-02 2 views
1
#include <iostream> 
#include <atomic> 
#include <array> 
#include <thread> 

template <typename T> 
struct node { 
    T  value; 
    node* next{nullptr}; 
}; 

typedef node<int> node_type; 

std::atomic<node_type*> _begin; 

node_type* get() { 
    node_type* b = _begin; 

    while (!_begin.compare_exchange_weak(b, b->next)) 
     ; 

    return b; 
} 

void give(node_type* v) { 
    v->next = _begin; 

    while (!_begin.compare_exchange_weak(v->next, v)) 
     ; 
} 

void get_and_give() { 
    for (int i = 0; i < 1000000; ++i) { 
     auto n = get(); 

     give(n); 
    } 
} 

int main(int argc, const char * argv[]) 
{ 
    std::array<node_type, 4> _nodes; 

    for (auto & i : _nodes) 
     give(&i); 

    std::thread t1(get_and_give); 
    std::thread t2(get_and_give); 
    std::thread t3(get_and_give); 

    get_and_give(); 

    t1.join(); 
    t2.join(); 
    t3.join(); 

    return 0; 
} 

Il y a une course (je crois) sur le pointeur suivant à l'intérieur de la valeur retournée par get. Cela ne se produit PAS avec 2 threads exécutant get_and_give, donc il semble que ce soit un manque de cohérence séquentielle dans les autres threads, mais tout ce que je fais est memory_order_seq_cst, donc je ne comprends pas comment cela pourrait être un problème?Où est la course?

Des idées!?

Répondre

3

Je suppose que vous êtes confronté à ce que l'on appelle le problème ABA.

De wikipedia

le problème de l'ABA se produit lors de la synchronisation, lorsqu'un emplacement est lu deux fois, a la même valeur pour les deux lectures, et « valeur est la même » est utilisé pour indiquer « rien n'a changé » . Cependant, un autre thread peut s'exécuter entre les deux lectures et changer la valeur, faire un autre travail, puis modifier la valeur, trompant ainsi le premier thread en pensant que «rien n'a changé», même si le second thread a fonctionné en violation de cette supposition.

+0

L'exemple sur wikipedia est presque mon code exact, donc c'est probablement ça! – pat