2010-08-25 10 views
7

Juste par curiosité, quelle est la meilleure façon d'obtenir une synchronisation interprocess sur Linux? La famille d'appels système sem*(2) semble avoir une interface très maladroite et datée, alors qu'il existe trois façons de verrouiller les fichiers - fcntl(), flock() et lockf().Verrouillage de fichier vs sémaphores

Quelles sont les différences internes (le cas échéant) et comment justifiez-vous l'utilisation de chacune?

Répondre

8

Ni l'un ni l'autre. Les versions actuelles de pthread_* (par exemple, phtread_mutex_t) permettent toutes de placer les variables dans des segments partagés créés via shm_open. Il suffit de placer un paramètre supplémentaire dans les appels init.

Ne pas utiliser sémaphores (sem_t) si vous n'avez pas, ils sont trop bas niveau et sont par IO interupted etc.

Ne pas abuser le verrouillage des fichiers pour le contrôle interprocessus. Ce n'est pas fait pour ça. En particulier, vous n'avez pas la possibilité de vider les méta-données de fichiers telles que les verrous, de sorte que vous ne savez jamais quand un verrou/déverrouillage deviendra visible à un second processus.

+0

Je me souviens que pthread_mutex_t dans une mémoire partagée rend parfois du mal, si je me souviens bien sur du noyau 2.4.x. Connaissez-vous quelque chose à ce sujet? – DarkDust

+0

@DarkDust: versions du noyau antérieures à 2.6.quelque chose (mais il y a de nombreuses années) avait une implémentation pthread différente, qui n'était en fait pas adaptée au contrôle interprocessus. C'est l'histoire. Quoi qu'il en soit, l'appel 'init' correspondant vous indiquera au retour si l'attribut' pshared' n'est pas supporté par l'implémentation. –

+0

Vous sacrifiez la portabilité avec cette technique? – bstpierre

2

Les différentes implémentations de verrouillage/sémaphore ont toutes pris vie sur différents systèmes. Sur le système V Unix vous aviez semget/semop, POSIX a défini une implémentation différente avec sem_init, sem_wait et sem_post. Et flock est originaire de BSD 4.2, autant que j'ai pu le découvrir.

Depuis qu'ils ont tous gagné une certaine importance, Linux les supporte tous maintenant pour faciliter le portage. En outre, flock est un mutex (verrouillé ou déverrouillé), mais les fonctions sem* (à la fois SysV et POSIX) sont des sémaphores: elles permettent à une application d'accorder plusieurs accès simultanés aux processus, par ex. vous pourriez autoriser l'accès à une ressource à 4 processus simultanés avec des sémaphores. Vous pouvez implémenter un mutex avec des sémaphores mais pas l'inverse. Je me souviens que dans l'excellent "Programmation avancée UNIX" par Marc J. Rochkind il a démontré comment transmettre des données entre processus via des sémaphores (très inefficace, il l'a fait juste pour prouver que cela peut être fait). Mais je n'ai rien trouvé de fiable sur l'efficacité.

Je suppose que c'est plus comme "Utilisez ce que vous voulez".

+0

Pourquoi un sémaphore ne peut-il pas être implémenté en utilisant des mutex? –

+1

@Anurag Uniyal: Parce qu'un mutex n'a que deux états: verrouillé ou déverrouillé. Un sémaphore est un compteur et a donc plus de deux états. – DarkDust

+0

Cela ne semble pas correct. Je ne vois pas pourquoi un sémaphore ne peut pas être fait en utilisant un mutex. –

4

Vous souffrez d'une multitude de choix d'une riche histoire, comme l'a noté DarkDust. Pour ce que ça vaut mon arbre de décision va quelque chose comme ceci:

Utilisez mutexes quand un seul processus/thread peut avoir accès à la fois.

Utilisez des sémaphores lorsque plusieurs processus/threads (mais néanmoins finis) peuvent utiliser une ressource.

Utilisez des sémaphores POSIX à moins que vous n'ayez vraiment besoin de quelque chose de sémaphore SYSV - par exemple. UNDO, PID de la dernière opération, etc.

Utilisez le verrouillage de fichier sur des fichiers ou si ceux-ci ne correspondent pas à vos exigences.

2

Une différence potentiellement significative pourrait être l'équité de la distribution des ressources. Je ne connais pas les détails de la mise en œuvre de la famille semget/semop, mais je soupçonne qu'elle est généralement implémentée comme un sémaphore "traditionnel" en ce qui concerne la planification. Généralement, je crois que les threads libérés sont gérés sur une base FIFO (le premier qui attend le sémaphore est libéré en premier).Je ne pense pas que cela se produirait avec le verrouillage de fichier car je suspecte (encore une fois de deviner) que la manipulation n'est pas effectuée au niveau du noyau. J'ai eu du code existant assis pour tester les sémaphores à des fins IPC, et j'ai donc comparé les deux situations (une utilisant semop et une utilisant lockf). J'ai fait un test d'un pauvre et j'ai juste couru à des instances de l'application. Le sémaphore partagé a été utilisé pour synchroniser le début. Lors de l'exécution du test semop, les deux processus ont terminé 3 millions de boucles presque synchronisées. La boucle de verrouillage, d'autre part, n'était pas aussi juste. Un processus se termine généralement alors que l'autre n'a complété que la moitié des boucles.

La boucle du test semop ressemblait à ceci. Les fonctions semwait et semsignal ne sont que des wrappers pour les appels semop.

ct = myclock(); 
    for (i = 0; i < loops; i++) 
     { 
     ret = semwait("test", semid, 0); 
     if (ret < 0) { perror("semwait"); break; } 

     if ((i & 0x7f) == 0x7f) 
     printf("\r%d%%", (int)(i * 100.0/loops)); 

     ret = semsignal(semid, 0); 
     if (ret < 0) { perror("semsignal"); break; } 
     } 
    printf("\nsemop time: %d ms\n", myclock() - ct); 

Le temps d'exécution total pour les deux méthodes était à peu près la même, bien que la version lockf était en fait parfois globalement plus rapide en raison de l'iniquité de la programmation. Une fois le premier processus terminé, l'autre processus aurait un accès incontesté pour environ 1,5 million d'itérations et serait extrêmement rapide.

Lors de l'exécution non contestée (processus unique obtenant et libérant les verrous), la version semop était plus rapide. Il a fallu environ 2 secondes pour 1 million d'itérations tandis que la version lockf a pris environ 3 secondes.

Cela a été exécuté sur la version suivante:

[]$ uname -r 
2.6.11-1.1369_FC4smp 
+0

Les sémaphores de système AFAIK dépendent entièrement du planificateur de système d'exploitation et n'ont pas d'intelligence propre. Bien que la politique générale d'ordonnancement des threads puisse être définie, la séquence de libération des threads sera indéterminée dans un sens pratique. – Duck

+0

@Duck, C'est certainement vrai; il serait faux de s'attendre à ce que les threads soient libérés dans un certain ordre. Mais votre point de sémaphores dépendant de l'OS est le point critique. Parce que le système d'exploitation prend la décision, il peut appliquer toutes les règles d'équité qu'il veut (qu'il s'agisse d'une approximation de FIFO ou même d'un retournement aléatoire de la pièce).Quand un verrou de fichier est libéré, je ne pense pas que le même type de prise de décision se produise dans le noyau. –

Questions connexes