2010-04-22 20 views
2

Je ne suis pas tout à fait sûr s'il est sûr de tourner sur une variable volatile dans les threads en mode utilisateur, pour mettre en œuvre un spin_lock léger, je regardais le code source de TBB, tbb_machine.h: 170,Est-il sécuritaire de tourner une variable volatile dans les threads en mode utilisateur?

//! Spin WHILE the value of the variable is equal to a given value 
/** T and U should be comparable types. */ 
template<typename T, typename U> 
void spin_wait_while_eq(const volatile T& location, U value) { 
    atomic_backoff backoff; 
    while(location==value) backoff.pause(); 
} 

Et il n'y a pas de clôture dans la classe atomic_backoff comme je peux le voir. Alors que d'autres implémentation spin_lock en mode utilisateur, la plupart d'entre eux utilisent CAS (Compare and Swap).

+1

Ce code est-il dans un '# ifdef' spécifique au compilateur ou similaire? Certains compilateurs implémentent des barrières de mémoire autour des accès "volatile". – jalf

+0

non, il n'y a pas #ifdef ou similaire autour de cet extrait. – yongsun

Répondre

2

Tricky. Je dirais que dans la théorie, ce code n'est pas sûr. S'il n'y a pas de barrière de mémoire, les accès aux données que vous surveillez pourraient être déplacés à travers le spinlock. Cependant, ceci ne serait fait que si le compilateur était très agressif et pouvait voir un but dans cette réorganisation.

Peut-être Intel simplement déterminé que ce code fonctionne sur tous les compilateurs actuels, et que même si un compilateur pourrait théoriquement effectuer des transformations qui brisaient ce code, ces transformations n'accélérer le programme, et donc probablement compilateurs ne le fera pas.

Une autre possibilité est que ce code est utilisé uniquement sur les compilateurs qui mettent en œuvre implicitement les barrières de mémoire autour volatile accès. Le compilateur Visual C++ de Microsoft (2005 et ultérieur) le fait. Avez-vous vérifié si cela est enveloppé dans un bloc #ifdef ou similaire, en appliquant cette implémentation uniquement sur les compilateurs où volatile utilisent des barrières de mémoire?

+0

"Peut-être que Intel a simplement déterminé que ce code fonctionne sur tous les compilateurs actuels". TBB n'est intrinsèquement pas portable. Probablement, ils ont déterminé que cela fonctionne sur tous les compilateurs/plates-formes qu'ils prennent en charge, pas nécessairement tous les compilateurs actuels. Quand ils disent que leur code fonctionne sur GCC, je soupçonne que cela ne signifie pas nécessairement qu'il fonctionne sur toutes les plates-formes que GCC cible. –

+0

@Steve: assez bien. Je sais que ce n'est pas portable. Ce que je voulais dire, c'est qu'ils se sentaient confiants que ça a marché sur 1) les compilateurs actuellement supportés et 2) les compilateurs qu'ils sont susceptibles de supporter dans le futur (principalement les nouvelles versions de ces compilateurs, comme VC2010 et GCC4.5) – jalf

+0

jalf, merci pour la réponse :) – yongsun

0

Notez qu'il s'agit d'un spin attendez et non un spin verrouiller. Il n'y a pas d'opération d'écriture impliquée. Rien n'est acquis.

Si vous avez essayé d'ajouter une opération d'écriture pour terminer le processus de verrouillage, vous auriez une course impossible à résoudre.

+0

@Potatoswatter, si j'ai besoin d'ajouter une opération d'écriture, que dois-je faire pour compléter cela? placer un load_with_acquire dans spin_wait_while_eq, et un store_with_release dans le writer? – yongsun

+0

@yongsun: Non. Utilisez une implémentation de bibliothèque, telle que 'pthread_mutex_lock'. J'imagine que TBB devrait aussi inclure quelque chose de approprié. Vous pouvez utiliser des variables atomiques pour rouler les vôtres, atomics étant tout ce que vous pouvez trouver qui implémente load_with_acquire et store_with_release. Mais ce sera probablement sous-optimal par rapport à n'importe quelle bibliothèque. – Potatoswatter