7
votes

Comment utiliser un fichier comme un mutex à Linux et C?

J'ai des processus différents accédant simultanément à un tuyau nommé sous Linux et je tiens à rendre cet accès mutuellement exclusif.

Je sais est possible de réaliser cela utilisant un mutex placé dans une zone de mémoire partagée, mais étant une sorte de Cession des devoirs J'ai quelques restrictions.

Ainsi, ce que je pensais, c'est d'utiliser des primitives de verrouillage sur des fichiers pour obtenir une exclusion mutuelle; J'ai fait essayer mais je ne peux pas le faire fonctionner.

C'est ce que j'ai essayé: xxx

Différents projets utiliseront différents descripteurs de fichiers mais en faisant référence au même fichier. Est-il possible d'atteindre quelque chose comme ça? Pouvez-vous fournir un exemple?


10 commentaires

Je ne peux pas utiliser de mutex! Je ne veux pas compliquer les choses, mais cela doit être fait de cette façon


Peut-être devriez-vous expliquer pourquoi vous voulez utiliser un fichier au lieu d'un vrai mutex ...


Parce que différents processus accéderont aux mêmes tuyaux à l'aide d'une bibliothèque statique et la bibliothèque statique est une exigence de projet


Je ne vois pas comment cela vous empêche de relier quelque chose comme Pthreads et en utilisant sa mise en œuvre mutex, cependant.


Je ne sais pas ... Je suis inquiet du fait que ce projet devra courir sur un ordinateur d'enseignant et ne peut pas demander des privilèges super utilisateurs


Quel type de mutex propose-t-il que les gens proposent devraient être utilisés? Il s'agit d'un système multi-processus afin que Pthread mutexes ne soit pas une option; Ils sont pour un seul processus multi-fileté.


@Jonathan Je ne connais pas les systèmes Pthread ou * Nix, mais sur Windows, le mutex est transversal. Il doit y avoir quelque chose de similaire sur * Nix Systems.


@Simone Vous n'avez pas besoin de droits super utilisateurs pour utiliser un mutex!


Mais j'ai besoin de droits super utilisateurs pour créer un lien vers une bibliothèque partagée juste? et de plus, si je relie une bibliothèque dynamique avec une bibliothèque statique, je n'aurai pas de statique mais une bibliothèque dynamique je pense


Vous n'avez pas besoin de droits super utilisateurs pour lier à la bibliothèque


3 Réponses :


5
votes

La technique de fichier de verrouillage standard utilise des options telles que o_excl sur le Ouvrir () appelez pour essayer de créer le fichier. Vous stockez le PID du processus à l'aide de la serrure. Vous pouvez donc déterminer si le processus existe toujours (en utilisant tuer () pour tester). Vous devez vous soucier de la concurrence - beaucoup.

Étapes:

  • Déterminez le nom du fichier de verrouillage basé sur le nom de FIFO
  • Fichier de verrouillage ouvert s'il existe
  • Vérifiez si le processus en utilisant elle existe
    • Si un autre processus existe, il contrôle un contrôle (sortie d'erreur ou attendez-le)
    • Si autre processus est absent, supprimez le fichier de verrouillage
    • À ce stade, le fichier de verrouillage n'existait pas lors de la dernière vérification.
    • Essayez de le créer avec Ouvrir () et o_excl parmi les autres options.
    • Si cela fonctionne, votre processus a créé le fichier - vous avez la permission d'aller de l'avant.
    • Écrivez votre PID au fichier; fermez-le.
    • Ouvrez la FIFO - utilisez-le.
    • Une fois terminé ( atexit () ?) Supprimez le fichier de verrouillage.

      S'inquiéter de ce qui se passe si vous ouvrez le fichier de verrouillage et lisez aucun PID ... Est-ce que un autre processus vient de le créer et n'a pas encore écrit son PID, ou a-t-il été mort avant de le faire? Probablement préférable de reculer - fermez le fichier et réessayez (éventuellement après un nanosleep () ). Si vous obtenez le fichier vide plusieurs fois (disons 3 dans une ligne) supposons que le processus est mort et supprimez le fichier de verrouillage.

      Vous pouvez envisager de disposer du processus qui possède le fichier maintenir un verrou de conseil sur le fichier pendant qu'elle dispose de la FIFO Open. Si la serrure est absente, le processus est mort. Il existe toujours un TOCTOU (heure de contrôle, heure d'utilisation) Fenêtre de vulnérabilité entre ouvrir le fichier et appliquer la serrure.

      Jetez un coup d'œil à la page Ouvrir () manuel de votre système pour voir s'il existe d'autres options pour vous aider. Parfois, les processus utilisent des répertoires ( mkdir () ) au lieu de fichiers car même root ne peut pas créer une seconde instance de nom de répertoire donné, mais vous avez des problèmes avec comment connaître le PID du processus avec la ressource ouverte, etc.


6 commentaires

autrement? J'ai également pensé à l'utilisation d'une troisième FIFO, puisque une FIFO bloque les lecteurs quand est vide..it est possible?


Je n'irais pas si loin de dire que c'est impossible, mais cela ne se sent pas juste en utilisant une FIFO pour obtenir un accès exclusif à une autre FIFO, et je ne sais pas comment cela fonctionnerait, de toute façon. Mais je n'ai pas passé longtemps à penser à la façon dont cela pourrait fonctionner.


Cette méthode est la bugprone: Les PID ne sont pas garantis d'être uniques et peuvent être réutilisés. Je ne vois pas pourquoi il y aurait un tutou entre ouvrir le fichier et le verrouiller. Pourquoi ne pas simplement utiliser flock , qui est publié automatiquement sur la sortie du programme?


@Cybershadow: Je n'ai pas prétendu que c'était libre de toutes les défauts possibles; Je viens de dire que c'était la technique standard. Unix est exécuté depuis des années en utilisant des variantes mineures de cette technique et survécu principalement. Il y a un toctou parce qu'il y a plusieurs appels système; Seul le système atomique appelle à la création de fichiers n'a pas de problèmes de TOCTOU. Vous pouvez utiliser flock () si vous le souhaitez; Ce n'est pas la technique standard, en partie parce que c'était une arrivée tardive sur la scène (quelque part dans les années 80, je crois). [... suite ...]


[... continuation ...] Un avantage possible du fichier de verrouillage est que s'il est présent, mais le processus n'est pas, vous pouvez le supposer que cela s'est écrasé et vous pouvez prendre des précautions supplémentaires pour assurer la Le fichier protégé est sain d'esprit. OTOH, il pourrait bien être mieux juste pour faire cette validation quand même.


ReC TOCTOU: La serrure agit de toute façon, ce qui ne fait pas pertinent combien de temps passe entre l'ouverture du fichier et le verrouiller. C'est le cas avec flock . La critique n'est pas personnelle, mais nous ne sommes pas dans les années 70 et il y a / il y a / devrait être de meilleures méthodes maintenant.



4
votes

Votre exemple est aussi bon que vous allez utiliser FLOCK (2) (qui est après tout, simplement un verrou "consultatif" (qui doit dire pas une serrure du tout, vraiment)). La page Homme pour celui-ci sur mon système Mac OS X a quelques provisoires éventuellement importantes:

Les serrures sont sur des fichiers et non des descripteurs de fichiers. C'est-à-dire que les descripteurs de fichiers dupliqués via DUP (2) ou Fourche (2) n'entraînent pas de nombreuses instances d'un Verrouiller, mais plusieurs références à une seule serrure. Si un processus tenant une serrure sur une fourchette de fichier et que l'enfant déverrouille explicitement le fichier, le le parent perdra sa serrure

et

Les processus bloqués en attente d'une serrure peuvent être réveillés par des signaux.

Les deux suggèrent les moyens d'échouer.


// aurait été un commentaire, mais je voulais citer la page d'homme à une certaine longueur


1 commentaires

Ce qui signifie qu'il est très important de vérifier la valeur de retour de flock () pour savoir que la serrure a réellement eu lieu (alors qu'un mutex réussit toujours à moins que cela ne bloque votre processus pour toujours).



5
votes

Je recommanderais certainement d'utiliser un mutex réel (comme cela a été suggéré dans les commentaires); Par exemple, la bibliothèque Pthf="http://linux.die.net/man/3/pthread_mutex_init" Rel="nofollow Noreferrer"> Une implémentation . Mais si vous voulez vous faire vous-même en utilisant un fichier à des fins éducatifs, je vous suggère de jeter un coup d'œil sur Cette réponse J'ai publié il y a quelque temps qui décrit une méthode pour le faire en python. Traduit en C, il devrait ressembler à ceci (avertissement: code non testé, utiliser à vos risques et périls; aussi mon C est rouillé):

// each instance of the process should have a different filename here
char* process_lockfile = "/path/to/hostname.pid.lock";
// all processes should have the same filename here
char* global_lockfile = "/path/to/lockfile";
// create the file if necessary (only once, at the beginning of each process)
FILE* f = fopen(process_lockfile, "w");
fprintf(f, "\n"); // or maybe write the hostname and pid
fclose(f);

// now, each time you have to lock the file:
int lock_acquired = 0;
while (!lock_acquired) {
    int r = link(process_lockfile, global_lockfile);
    if (r == 0) {
        lock_acquired = 1;
    }
    else {
        struct stat buf;
        stat(process_lockfile, &buf);
        lock_acquired = (buf.st_nlink == 2);
    }
}
// do your writing
unlink(global_lockfile);
lock_acquired = 0;


2 commentaires

Nice, mais l'attente occupée doit être évitée. Sur BSD / DARWIN, on peut utiliser kQQuue pour cela, avec evfilt_vnode et evfilt_proc . Une méthode existe probablement sur Linux également.


Le principal problème avec la méthode est que la verrouille restera si le programme se termine de manière anormale (bogue / crash / signal / arrêt du système). FLOCK n'a pas ce problème.