Il existe de nombreuses fonctions de veille en langage C. Souvent, je ne sais pas où utiliser quoi. Cela dit, vous ne pouvez pas être un vrai programmeur C si vous choisissez correctement la fonction de veille. Les programmeurs C ont pour mission de choisir la meilleure des nombreuses options et d'offrir des performances inégalées.
Dans cet article, j'écrirai sur la différence entre usleep, nanosleep et clock_nanosleep, qui peuvent réaliser un traitement du sommeil très précis.
La version cible du noyau Linux est ** 5.4.2 **.
Après cette section, je lirai le code source du noyau Linux, mais je ne le sais pas, donc pour ceux qui veulent donner une conclusion rapidement, j'écrirai d'abord la conclusion.
Comment, ces trois fonctions font *** presque le même comportement ***!
Seul clock_nanosleep peut changer son comportement en fonction de l'argument, mais si vous passez CLOCK_MONOTONIC comme premier argument de clock_nanosleep, le comportement des trois fonctions sera le même.
Cependant, chacune de ces fonctions a une utilisabilité différente. Il semble préférable d'utiliser une fonction facile à appeler dans chaque situation. Si vous souhaitez vous assurer qu'ils correspondent au niveau du code source, consultez les sections suivantes.
Voyons quels sont les types de fonctions usleep, nanosleep et clock_nanosleep. Ces informations sont tirées du manuel du programmeur Linux de l'homme.
usleep usleep-Différer l'exécution en microsecondes
#include <unistd.h>
int usleep(useconds_t usec);
nanosleep sommeil de haute précision nanosleep
#include <time.h>
int nanosleep(const struct timespec *req, struct timespec *rem);
clock_nanosleep clock_nanosleep - Arrêt précis (veille) à l'horloge spécifiée
#include <time.h>
int clock_nanosleep(clockid_t clock_id, int flags,
const struct timespec *request,
struct timespec *remain);
Eh bien, ce que je veux faire est presque la même chose. Je veux dormir au niveau de la nanoseconde.
Ensuite, je voudrais classer chaque fonction par appel système ou fonction de bibliothèque. (Eh bien, les appels système fournissent également une interface côté bibliothèque pour envelopper l'assembleur, mais ici nous les classons selon qu'ils sont définis comme des appels système du noyau Linux ou non.)
usleep | nanosleep | clock_nanosleep |
---|---|---|
Fonction bibliothèque | Appel système | Appel système |
Ça ressemble à ça.
Examinons maintenant chaque fonction au niveau du code source.
usleep
Regardons maintenant la définition de usleep.
usleep est une fonction définie par la glibc et n'est pas un appel système Linux. Vous pouvez alors vous attendre à ce que usleep appelle un appel système pour faire dormir dans cette fonction. Quand j'ai examiné le code source de la glibc, c'était comme suit.
https://github.com/lattera/glibc/blob/master/sysdeps/posix/usleep.c
int
usleep (useconds_t useconds)
{
struct timespec ts = { .tv_sec = (long int) (useconds / 1000000),
.tv_nsec = (long int) (useconds % 1000000) * 1000ul };
/* Note the usleep() is a cancellation point. But since we call
nanosleep() which itself is a cancellation point we do not have
to do anything here. */
return __nanosleep (&ts, NULL);
}
En regardant ce code source et ses commentaires, usleep semble appeler l'appel système nanosleep. En d'autres termes *** glibc "N'est-il pas gênant de créer une structure timespec pour l'argument de nanosleep? J'ai défini une fonction wrapper." *** Il est défini comme tel. Par conséquent, on peut dire que usleep est une fonction qui reçoit des microsecondes, génère une structure timespec basée sur elle, et appelle finalement l'appel système nanosleep. Pour l'instant, je sais que usleep et nanosleep se comporteront de la même manière.
nanosleep Comme nanosleep est un appel système Linux, nous lirons le code source du noyau Linux. nanosleep est défini comme un appel système /kernel/time/hrtimer.c line:1945 https://elixir.bootlin.com/linux/v5.4.2/source/kernel/time/hrtimer.c#L1945 est.
SYSCALL_DEFINE2(nanosleep, struct __kernel_timespec __user *, rqtp,
struct __kernel_timespec __user *, rmtp)
{
struct timespec64 tu;
if (get_timespec64(&tu, rqtp))
return -EFAULT;
if (!timespec64_valid(&tu))
return -EINVAL;
current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
current->restart_block.nanosleep.rmtp = rmtp;
return hrtimer_nanosleep(&tu, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
}
Vous pouvez enfin voir que nous appelons une fonction appelée hrtimer_nanosleep. Cette fonction est une fonction qui exécute le traitement du sommeil à l'aide d'une minuterie de haute précision appelée Minuterie haute résolution. CLOCK_MONOTONIC est passé au troisième argument de la fonction hrtimer_nanosleep. Oh, cela aurait dû être une constante qui pourrait également être transmise à clock_nanosleep. Maintenant que j'ai senti quelque chose, jetons un coup d'œil à l'implémentation de l'appel système clock_nanosleep.
clock_nanosleep Enfin, lisez le code source de clock_nanosleep. Cet appel système /kernel/time/posix-stubs.c line: 124 https://elixir.bootlin.com/linux/v5.4.2/source/kernel/time/posix-stubs.c#L124 Il est défini dans.
SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
const struct __kernel_timespec __user *, rqtp,
struct __kernel_timespec __user *, rmtp)
{
struct timespec64 t;
switch (which_clock) {
case CLOCK_REALTIME:
case CLOCK_MONOTONIC:
case CLOCK_BOOTTIME:
break;
default:
return -EINVAL;
}
if (get_timespec64(&t, rqtp))
return -EFAULT;
if (!timespec64_valid(&t))
return -EINVAL;
if (flags & TIMER_ABSTIME)
rmtp = NULL;
current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
current->restart_block.nanosleep.rmtp = rmtp;
return hrtimer_nanosleep(&t, flags & TIMER_ABSTIME ?
HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
which_clock);
}
Cette fonction vérifie d'abord l'ID d'horloge spécifié. À part CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_BOOTTIME, il semble qu'une erreur se produira. Après lecture, ***, à l'exception de la vérification des drapeaux, cela fait presque la même chose que la définition de l'appel système nanosleep que nous avons vu dans la section précédente. *** ***
Pour le moment, la description est différente de nanosleep
flags & TIMER_ABSTIME ?
HRTIMER_MODE_ABS : HRTIMER_MODE_REL
Je vais également expliquer brièvement cette partie. Les indicateurs sont des indicateurs qui peuvent être passés à l'appel système clock_nanosleep. Si cet indicateur est défini sur *** TIMER_ABSTIME ***, HRTIMER_MODE_ABS sera transmis à la fonction *** hrtimer_nanosleep ***. Selon la description de man, si le drapeau *** TIMER_ABSTIME *** est spécifié,
** Si flags est TIMER_ABSTIME, l'argument reste n'est pas utilisé et n'est pas nécessaire (l'arrêt à une valeur absolue peut être appelé à nouveau avec le même argument de requête). ** **
est ce qu'ils ont dit. En d'autres termes, j'ai trouvé que ce processus a été ajouté pour gérer l'indicateur clock_nanosleep.
J'ai dit la conclusion ci-dessus, mais apparemment ces trois fonctions se comportent à peu près de la même manière. En d'autres termes, chaque méthode appelle finalement la fonction hrtimer_nanosleep, et le processus de détermination des arguments à transmettre à cette fonction est différent. Si je vous force à faire une différence, je pense que c'est cette flexibilité. Bien que usleep et nanosleep ne puissent utiliser CLOCK_MONOTONIC que comme indicateur de veille, clock_nanosleep peut être librement décidé par le programmeur.
La conclusion était qu'il n'y avait pas beaucoup de différence à la fin, mais une culture open source était essentielle pour arriver à cette conclusion. Le meilleur open source, j'espère que le logiciel libre continuera à se développer!
Recommended Posts