Sous Linux, qu'arrive-t-il à l'état d'un processus lorsqu'il a besoin de lire des blocs à partir d'un disque? Est-ce bloqué? Si oui, comment un autre processus est-il choisi pour s'exécuter?
Réponses:
En attendant read()
ou write()
vers / depuis un retour de descripteur de fichier, le processus sera placé dans un type spécial de sommeil, appelé «D» ou «Disk Sleep». Ceci est spécial, car le processus ne peut pas être tué ou interrompu dans un tel état. Un processus en attente d'un retour de ioctl () serait également mis en veille de cette manière.
Une exception à ceci est quand un fichier (tel qu'un terminal ou un autre périphérique de caractères) est ouvert en O_NONBLOCK
mode, passé quand il suppose qu'un périphérique (tel qu'un modem) aura besoin de temps pour s'initialiser. Cependant, vous avez indiqué bloquer les périphériques dans votre question. Aussi, je n'ai jamais essayé un ioctl()
qui est susceptible de bloquer sur un fd ouvert en mode non bloquant (du moins pas sciemment).
La façon dont un autre processus est choisi dépend entièrement du planificateur que vous utilisez, ainsi que de ce que d'autres processus auraient pu faire pour modifier leurs poids dans ce planificateur.
Certains programmes d'espace utilisateur dans certaines circonstances sont connus pour rester dans cet état pour toujours, jusqu'à leur redémarrage. Ceux-ci sont généralement regroupés avec d'autres «zombies», mais le terme ne serait pas correct car ils ne sont pas techniquement périmés.
Lorsqu'un processus a besoin d'extraire des données d'un disque, il arrête effectivement de s'exécuter sur le processeur pour permettre à d'autres processus de s'exécuter car l'opération peut prendre beaucoup de temps - au moins 5 ms de temps de recherche pour un disque sont courants, et 5 ms équivaut à 10 millions Cycles CPU, une éternité du point de vue du programme!
Du point de vue du programmeur (également dit "dans l'espace utilisateur"), cela s'appelle un appel système bloquant . Si vous appelez write(2)
(qui est un fin wrapper de libc autour de l'appel système du même nom), votre processus ne s'arrête pas exactement à cette limite; il continue, dans le noyau, à exécuter le code d'appel système. La plupart du temps, il va jusqu'à un pilote de contrôleur de disque spécifique (nom de fichier → système de fichiers / VFS → périphérique de bloc → pilote de périphérique), où une commande pour récupérer un bloc sur le disque est soumise au matériel approprié, ce qui est très fonctionnement rapide la plupart du temps.
ALORS le processus est mis en état de veille (dans l'espace noyau, le blocage est appelé endormi - rien n'est jamais «bloqué» du point de vue du noyau). Il sera réveillé une fois que le matériel aura finalement récupéré les données appropriées, puis le processus sera marqué comme exécutable et sera planifié. Finalement, le planificateur exécutera le processus.
Enfin, dans l'espace utilisateur, l' appel système de blocage retourne avec le statut et les données appropriés, et le déroulement du programme se poursuit.
Il est possible d'appeler la plupart des appels système d'E / S en mode non bloquant (voir O_NONBLOCK
dans open(2)
et fcntl(2)
). Dans ce cas, les appels système retournent immédiatement et signalent uniquement la soumission de l'opération de disque. Le programmeur devra vérifier explicitement ultérieurement si l'opération s'est terminée, avec succès ou non, et récupérer son résultat (par exemple, avec select(2)
). C'est ce qu'on appelle la programmation asynchrone ou basée sur les événements.
La plupart des réponses ici mentionnant l' état D (qui est appelé TASK_UNINTERRUPTIBLE
dans les noms d'état Linux) sont incorrectes. L' état D est un mode de veille spécial qui n'est déclenché que dans un chemin de code de l'espace noyau, lorsque ce chemin de code ne peut pas être interrompu (car il serait trop complexe à programmer), dans l'espoir qu'il ne bloquerait que pour un très court instant. Je crois que la plupart des "états D" sont en fait invisibles; ils sont de très courte durée et ne peuvent pas être observés par des outils d'échantillonnage tels que «top».
Vous pouvez rencontrer des processus impossibles à tuer à l'état D dans quelques situations. NFS est célèbre pour cela, et je l'ai rencontré plusieurs fois. Je pense qu'il y a un conflit sémantique entre certains chemins de code VFS, qui supposent toujours atteindre les disques locaux et une détection rapide des erreurs (sur SATA, un délai d'attente d'erreur serait d'environ 100 ms), et NFS, qui récupère en fait les données du réseau qui est plus résilient et a une récupération lente (un délai TCP de 300 secondes est courant). Lisez cet article pour la solution cool introduite dans Linux 2.6.25 avec l' TASK_KILLABLE
état. Avant cette ère, il y avait un hack où vous pouviez envoyer des signaux aux clients de processus NFS en envoyant un SIGKILL au thread du noyau rpciod
, mais oubliez cette vilaine astuce.…
/proc/stat
?
Un processus effectuant des E / S sera mis à l' état D (veille ininterrompue) , ce qui libère le CPU jusqu'à ce qu'il y ait une interruption matérielle qui indique au CPU de reprendre l'exécution du programme. Voir man ps
pour les autres états de processus.
En fonction de votre noyau, il existe un planificateur de processus , qui assure le suivi d'une file d'attente de processus prêts à être exécutés. Il, avec un algorithme de planification, indique au noyau quel processus affecter à quel CPU. Il y a des processus du noyau et des processus utilisateur à prendre en compte. Chaque processus se voit attribuer une tranche de temps, qui est une partie du temps CPU qu'il est autorisé à utiliser. Une fois que le processus utilise toute sa tranche de temps, il est marqué comme expiré et reçoit une priorité inférieure dans l'algorithme de planification.
Dans le noyau 2.6 , il existe un planificateur de complexité temporelle O (1) , donc quel que soit le nombre de processus en cours d'exécution, il attribuera des processeurs en temps constant. C'est plus compliqué cependant, puisque 2.6 a introduit la préemption et que l'équilibrage de la charge du processeur n'est pas un algorithme facile. Dans tous les cas, c'est efficace et les CPU ne resteront pas inactifs pendant que vous attendez les E / S.
Comme déjà expliqué par d'autres, les processus à l'état "D" (sommeil ininterrompu) sont responsables du blocage du processus ps. Pour moi, cela s'est produit à plusieurs reprises avec RedHat 6.x et les répertoires personnels NFS montés automatiquement.
Pour répertorier les processus à l'état D, vous pouvez utiliser les commandes suivantes:
cd /proc
for i in [0-9]*;do echo -n "$i :";cat $i/status |grep ^State;done|grep D
Pour connaître le répertoire actuel du processus et, peut-être, le disque NFS monté qui présente des problèmes, vous pouvez utiliser une commande similaire à l'exemple suivant (remplacez 31134 par le numéro du processus en veille):
# ls -l /proc/31134/cwd
lrwxrwxrwx 1 pippo users 0 Aug 2 16:25 /proc/31134/cwd -> /auto/pippo
J'ai trouvé que donner la commande umount avec le commutateur -f (force), au système de fichiers nfs monté associé, était capable de réveiller le processus de veille:
umount -f /auto/pippo
le système de fichiers n'a pas été démonté, car il était occupé, mais le processus associé s'est réveillé et j'ai pu résoudre le problème sans redémarrer.
En supposant que votre processus est un seul thread et que vous utilisez des E / S bloquantes, votre processus se bloquera en attendant la fin des E / S. Le noyau choisira un autre processus à exécuter entre-temps en fonction de la gentillesse, de la priorité, de la dernière exécution, etc. S'il n'y a pas d'autres processus exécutables, le noyau n'en exécutera aucun; au lieu de cela, il indiquera au matériel que la machine est inactive (ce qui réduira la consommation d'énergie).
Les processus qui attendent la fin des E / S apparaissent généralement dans l'état D dans, par exemple, ps
et top
.
Oui, la tâche est bloquée lors de l'appel système read (). Une autre tâche qui est prête s'exécute, ou si aucune autre tâche n'est prête, la tâche inactive (pour cette CPU) s'exécute.
Une lecture de disque normale et bloquante amène la tâche à entrer dans l'état "D" (comme d'autres l'ont noté). Ces tâches contribuent à la charge moyenne, même si elles ne consomment pas le processeur.
Certains autres types d'E / S, en particulier ttys et réseau, ne se comportent pas tout à fait de la même manière - le processus se retrouve à l'état "S" et peut être interrompu et ne compte pas dans la moyenne de charge.
Oui, les tâches en attente d'E / S sont bloquées et d'autres tâches sont exécutées. La sélection de la tâche suivante est effectuée par le planificateur Linux .
Généralement, le processus se bloque. Si l'opération de lecture est sur un descripteur de fichier marqué comme non bloquant ou si le processus utilise des E / S asynchrones, il ne bloquera pas. De plus, si le processus a d'autres threads qui ne sont pas bloqués, ils peuvent continuer à s'exécuter.
La décision quant au processus qui s'exécute ensuite appartient au planificateur dans le noyau.