La Performance de pthread_mutex_lock/déverrouiller
J'ai remarqué que je prends un assez grand rendement frappé, quand j'ai un algorithme qui se verrouille et se déverrouille d'un thread BEAUCOUP.
Est-il un moyen pour aider à cette surcharge de travail? En utilisant un sémaphore être plus ou moins efficace?
Grâce
typedef struct _treenode{
struct _treenode *leftNode;
struct _treenode *rightNode;
int32_t data;
pthread_mutex_t mutex;
}TreeNode;
pthread_mutex_t _initMutex = PTHREAD_MUTEX_INITIALIZER;
int32_t insertNode(TreeNode **_trunk, int32_t data){
TreeNode **current;
pthread_mutex_t *parentMutex = NULL, *currentMutex = &_initMutex;
if(_trunk != NULL){
current = _trunk;
while(*current != NULL){
pthread_mutex_lock(&(*current)->mutex);
currentMutex = &(*current)->mutex;
if((*current)->data < data){
if(parentMutex != NULL)
pthread_mutex_unlock(parentMutex);
pthreadMutex = currentMutex;
current = &(*current)->rightNode;
}else if((*current)->data > data){
if(parentMutex != NULL)
pthread_mutex_unlock(parentMutex);
parentMutex = currentMutex;
current = &(*current)->leftNode;
}else{
pthread_mutex_unlock(currentMutex);
if(parentMutex != NULL)
pthread_mutex_unlock(parentMutex);
return 0;
}
}
*current = malloc(sizeof(TreeNode));
pthread_mutex_init(&(*current)->mutex, NULL);
pthread_mutex_lock(&(*current)->mutex);
(*current)->leftNode = NULL;
(*current)->rightNode = NULL;
(*current)->data = data;
pthread_mutex_unlock(&(*current)->mutex);
pthread_mutex_unlock(currentMutex);
}else{
return 1;
}
return 0;
}
int main(){
int i;
TreeNode *trunk = NULL;
for(i=0; i<1000000; i++){
insertNode(&trunk, rand() % 50000);
}
}
Un sémaphore ne différent (plus complexe) des choses et il est plus probable plus lent. Quel est ton OS? Pouvez-vous faire de la serrure plus fine-grain afin de ne pas bloquer aussi longtemps?
Ou de les rendre plus à grain grossier/faire plus de travail par verrouillage, de sorte que vous n'avez pas de changements de contexte. Il y a un bel équilibre.
Si vous afficher/décrire l'algorithme que nous pourrions donner des conseils. La solution: utiliser moins de verrouillage (répartir le travail sur des cœurs, de sorte que vous n'avez pas besoin de verrouiller les sous-régions) ou de le rendre lockfree (haaaaaaard). Rien d'autre, mais Moores Loi va aider
Certains algorithmes sont intrinsèquement série plus que d'autres. Mais de verrouillage et de limiter l'accès pour obtenir un résultat correct est mieux que pas de verrouillage et d'obtenir un résultat incorrect plus rapide.
bon point, merci pour ça. Une règle d'or: ne pas verrouiller l'échelle longue ops comme réseau ou d'un fichier I/O si vous pouvez l'aider.
Ou de les rendre plus à grain grossier/faire plus de travail par verrouillage, de sorte que vous n'avez pas de changements de contexte. Il y a un bel équilibre.
Si vous afficher/décrire l'algorithme que nous pourrions donner des conseils. La solution: utiliser moins de verrouillage (répartir le travail sur des cœurs, de sorte que vous n'avez pas besoin de verrouiller les sous-régions) ou de le rendre lockfree (haaaaaaard). Rien d'autre, mais Moores Loi va aider
Certains algorithmes sont intrinsèquement série plus que d'autres. Mais de verrouillage et de limiter l'accès pour obtenir un résultat correct est mieux que pas de verrouillage et d'obtenir un résultat incorrect plus rapide.
bon point, merci pour ça. Une règle d'or: ne pas verrouiller l'échelle longue ops comme réseau ou d'un fichier I/O si vous pouvez l'aider.
OriginalL'auteur poy | 2011-06-23
Vous devez vous connecter pour publier un commentaire.
Au lieu de se soucier des brins d'herbe, un pas en arrière et observer l'ensemble de la forêt.
De l'algorithme qui dépend de deux threads potentiellement près de nous marcher sur les uns des autres orteils, est intrinsèquement inefficace. Essayez de trouver un moyen de réduire considérablement le besoin d'interaction.
Par exemple, si un thread produit des données et de l'autre il consomme, on peut facilement imaginer un algorithme inefficace lorsque le producteur publie les données dans la mémoire partagée, et puis attend de l'autre pour en consommer. Pendant ce temps, le consommateur est en attente pour le producteur de finition, etc., etc. C'est beaucoup simplifié par le producteur de l'écriture dans un fichier ou un tuyau, et le consommateur de la lecture.
OriginalL'auteur wallyk
pthread_mutex_lock
etpthread_mutex_unlock
les coûts varient en fonction de la contention:Encore, mutex doit être le moins cher de verrouillage primitive dans la plupart des situations et sur la plupart des implémentations. Parfois spinlocks peut faire mieux. Je n'aurais jamais attendre les sémaphores à faire mieux.
Peut-être que je me dois de préciser: j'ai été en le comparant à une paire de trivial appels de fonction externe, c'est à dire le rendement que vous obtiendrez si
pthread_mutex_lock
etpthread_mutex_unlock
quasi-vide (fonctions, mais ne peut toujours pas être insérée et encore de l'installation d'un cadre de pile). Je n'ai pas les chiffres devant moi, mais je pense que le "no-op verrous" cas arriverez près de 80 cycles, sauf peut-être sur le haut de gamme des machines x86.Pour un simple producteur/consommateur basé sur un atomique de l'anneau, un feu de signalisation lorsqu'il existe des données disponibles peut surpasser une variable de condition / mutex comme pour ce dernier, les producteurs doivent également verrouiller à changer la condition.
Ma remarque sur les sémaphores était en référence à l'aide d'un sémaphore binaire comme un verrou. Mon intuition est que ce qui devrait, au mieux, en adéquation avec les performances d'un mutex, mais peut aussi être un peu pire. En particulier, les sémaphores POSIX ont certaines propriétés qui pourraient les rendre plus coûteux -- capacité à agir en annulation, à condition que l'opération post-être async-signal-coffre-fort (ce qui limite la mise en œuvre des choix), etc. Aussi, tandis que le prochain numéro de POSIX peut desserrer mutex exigences en matière de permis d'acquisition/diffusion de la sémantique, les sémaphores va sûrement rester "seq_cst".
OriginalL'auteur R..
Aussi loin que je peux voir votre serrure stratégie n'est pas optimale puisque la plupart des serrures ne seront pas prises pour modifier les données, mais seulement à lire et à trouver le chemin à travers l'arbre.
pthread_rwlock_t
pourrait de l'aide sur ce. Vous ne prenez en lecture des verrous sur le chemin vers le bas dans l'arbre jusqu'à ce que vous a frappé un noeud sur lequel vous voulez effectuer une modification. Il vous faudra alors prendre en écriture verrouillage. Par que vous pourriez avoir d'autres threads exécutent la même tâche lors de la marche en bas de l'arbre dans une autre branche sans déranger les uns les autres.Un décent de mise en œuvre de
pthread_rwlock_t
cela avec un compteur pour les lecteurs que cela change avec les opérations atomiques, tant qu'il n'y a pas de conflit avec les écrivains. Cela devrait être très rapide. Une fois qu'un conflit, il serait aussi coûteux qu'un mutex, je pense.désolé sa
pthread_rwlock_t
. Et il faut juste être là, dans<pthread.h.
si elle est mise en œuvre sur votre système.et Jens. 1) RWLocks ne sont pas toujours une meilleure solution. Si toutes les opérations de lecture prendre très court et à toutes les opérations d'écriture, leurs frais généraux par rapport à MutEx peut facilement tuer leur conceptuel avantage. Il dépend du nombre de lecteurs et d'écrivains et combien de fois ils ont frappé la section en parallèle. 2) pour autant Que je sais, RWLocks sont construites au-dessus de Mutex, mais même si pas, ils sont plus chers que MuitExes. 3) je voudrais utiliser un seul RWLock pour l'ensemble de l'arbre si l'écriture se produit rarement. Ensuite, tous les lecteurs peuvent obtenir heureux en parallèle.
OriginalL'auteur Jens Gustedt
Vos serrures sont probablement trop fines. Bien sûr, la meilleure granularité peut varier en fonction de la charge de travail.
Vous pouvez utiliser un verrou unique pour l'ensemble de l'arbre, et il peut faire mieux. Mais, si tu fais beaucoup de lecture et relativement peu d'insertions/délétions, vous vous retrouvez avec l'ensemble de l'arbre verrouillé souvent pour aucune bonne raison. Vous souhaiterez peut-être utiliser un lecteur-écrivain de verrouillage, ce qui permettrait à plusieurs lecteurs en même temps.
Votre question m'a rappelé de cette autre, quand il y a une comparaison entre les beaux-verrouillage et gros grain de verrouillage pour une liste liée. Alors que dans la version coarse-grain chaque thread exécuté à son tour (et non en parallèle), et le temps total d'exécution est légèrement plus que la somme de chaque fil du temps d'exécution, et dans la version fine-grain temps total d'exécution est beaucoup moins que la somme de chaque fil du temps d'exécution, la charge supplémentaire des beaux-verrouillage totalement compenser ces prestations, en faisant la fine version plus lente que les gros grains.
OriginalL'auteur ninjalj
De verrouillage et de déverrouillage sont très coûteuses opérations en cas de pthread_mutex_lock/déverrouiller. Plus de détails sur l'algorithme que je puisse faire des suggestions, mais aussi loin que je peux dire que je ne peux rien vous dire pour certains. Les sémaphores sont une alternative (encore une fois selon l'algorithme) et aussi des obstacles sont une autre méthode utile pour la concurrence. Pour aider à la surcharge, vous pouvez faire des choses comme créer vos serrures petite granularité ou une plus grande granularité. les verrous à l'intérieur de la boucle itérer plusieurs fois sont une mauvaise idée et vous pouvez les déplacer à l'extérieur de la boucle. C'est juste un exemple, mais il y a probablement plus que je peux venir avec. C'est sur la façon de déterminer si le coût de la serrure est plus grande que celle de la section critique de votre code. Si vous fournissez votre algorithme ou un exemple de code, je serais heureux de prendre un coup d'oeil.
OriginalL'auteur Jesus Ramos