2010-05-12 6 views
4

Je suis très intéressé par l'utilisateur-espace RCU (lecture-copie-mise à jour), et en essayant de simuler un via tr1 :: shared_ptr, voici le code, alors que je suis vraiment un débutant en programmation concurrente, certains experts m'aider à revoir?Utiliser shared_ptr pour implémenter RCU (read-copy-update)?

L'idée de base est que le lecteur appelle get_reading_copy() pour obtenir le pointeur des données protégées actuelles (disons qu'il s'agit de la génération un, ou G1). L'auteur appelle get_updating_copy() pour obtenir une copie du G1 (disons que c'est G2), et un seul auteur est autorisé à entrer dans la section critique. Une fois la mise à jour terminée, l'auteur appelle update() pour faire un échange et fait pointer m_data_ptr vers les données G2. Les lecteurs en cours et l'auteur maintiennent maintenant les shared_ptr (s) de G1, et un lecteur ou un écrivain finira par libérer les données G1.

Tous les nouveaux lecteurs obtiendraient le pointeur vers G2, et un nouvel auteur obtiendrait la copie de G2 (disons que c'est G3). Il est possible que le G1 ne soit pas encore sorti, donc plusieurs générations de données peuvent coexister.

template <typename T> 
class rcu_protected 
{ 
public: 
    typedef T         type; 
    typedef const T        const_type; 
    typedef std::tr1::shared_ptr<type>   rcu_pointer; 
    typedef std::tr1::shared_ptr<const_type> rcu_const_pointer; 

    rcu_protected() : m_is_writing(0), 
         m_is_swapping(0), 
         m_data_ptr (new type()) 
    {} 

    rcu_const_pointer get_reading_copy() 
    { 
     spin_until_eq (m_is_swapping, 0); 

     return m_data_ptr; 
    } 

    rcu_pointer get_updating_copy() 
    { 
     spin_until_eq (m_is_swapping, 0); 

     while (!CAS (m_is_writing, 0, 1)) 
     {/* do sleep for back-off when exceeding maximum retry times */} 

     rcu_pointer new_data_ptr(new type(*m_data_ptr)); 

     // as spin_until_eq does not have memory barrier protection, 
     // we need to place a read barrier to protect the loading of 
     // new_data_ptr not to be re-ordered before its construction 
     _ReadBarrier(); 

     return new_data_ptr; 
    } 

    void update (rcu_pointer new_data_ptr) 
    { 
     while (!CAS (m_is_swapping, 0, 1)) 
     {} 

     m_data_ptr.swap (new_data_ptr); 

     // as spin_until_eq does not have memory barrier protection, 
     // we need to place a write barrier to protect the assignments of 
     // m_is_writing/m_is_swapping be re-ordered bofore the swapping 
     _WriteBarrier(); 

     m_is_writing = 0; 
     m_is_swapping = 0; 
    } 

private: 
    volatile long m_is_writing; 
    volatile long m_is_swapping; 
    rcu_pointer m_data_ptr; 
}; 
+0

Je devrais utiliser rw_mutex pour protéger la lecture et la mise à jour, merci [email protected] pour la revue ... – yongsun

Répondre

1

D'un premier coup d'œil, j'échanger les spin_until_eq appels et spinlocks associés, pour un mutex. Si plus d'un auteur était autorisé dans la section critique, j'utiliserais un sémaphore. Ces implémentations de mécanismes de concurrence peuvent dépendre du système d'exploitation, de sorte que les considérations de performances doivent également être prises en compte; Habituellement, ils sont meilleurs que les attentes occupées.