[LINUX] Quelle est la différence entre usleep, nanosleep et clock_nanosleep?

introduction

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.

Laisse la blague de côté

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 **.

Première conclusion

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.

De quel type de fonction s'agit-il en premier lieu?

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.

Appel système ou fonction de bibliothèque

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.

Lisez et voyez le 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.

Conclusion après lecture du code source

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.

en conclusion

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

Quelle est la différence entre usleep, nanosleep et clock_nanosleep?
Quelle est la différence entre «pip» et «conda»?
Quelle est la différence entre Unix et Linux?
Quelle est la différence entre les liens symboliques et les liens durs?
À propos de la différence entre "==" et "is" en python
[Introduction à Python] Quelle est la différence entre une liste et un taple?
Différence entre == et est en python
[Introduction au modèle des maladies infectieuses] Quelle est la différence entre l'épidémie d'avril et cette épidémie? .. .. ‼
La réponse de "1/2" est différente entre python2 et 3
À propos de la différence entre PostgreSQL su et sudo
Prise en compte de la différence entre la courbe ROC et la courbe PR
Différence approximative entre Unicode et UTF-8 (et ses compagnons)
BERT peut-il comprendre la différence entre «Ame (bonbons)» et «Ame (pluie)»?
Comment utiliser argparse et la différence entre optparse
Différence entre processus et travail
Différence entre régression et classification
[Python] Python et sécurité-① Qu'est-ce que Python?
Différence entre np.array et np.arange
Différence entre MicroPython et CPython
A quoi sert l'interface ...
Qu'est-ce que la fonction de rappel?
Différence entre ps a et ps -a
Différence entre return et print-Python
Comprendre la différence entre l'affectation cumulative aux variables et l'affectation cumulative aux objets
Différence entre les back_populates et backref de SQL Alchemy et lorsque ni l'un ni l'autre n'est utilisé
Différence entre le processus de premier plan et le processus d'arrière-plan compris par principe
Différence entre Ruby et Python Split
Différence entre java et python (mémo)
Mémorandum (différence entre csv.reader et csv.dictreader)
[Python] Qu'est-ce que @? (À propos des décorateurs)
(Remarque) Différence entre la passerelle et la passerelle par défaut
[python] Quelle est la clé triée?
Différence entre le randint de Numpy et le randint de Random
Différence entre tri et tri (mémorial)
Différence entre la série python2 et la série python3 dict.keys ()
Qu'est-ce que le système X Window?
À quoi sert le trait de soulignement Python (_)?
J'ai étudié le comportement de la différence entre lien dur et lien symbolique
[Python] Différence entre fonction et méthode
Différence entre SQLAlchemy flush () et commit ()
[Python] Notation inclusive. Écrivez une déclaration simple pour. (Une collection est la différence entre un itérable et un itérateur)
Python - Différence entre exec et eval
[Python] Différence entre randrange () et randint ()
[Python] Différence entre trié et trié (Colaboratoire)
[Xg boost] Différence entre softmax et softprob
différence entre les instructions (instructions) et les expressions (expressions) en Python
[Django ORM] Différence entre values () et only ()
Différences dans la relation entre PHP et Python enfin et quitter
Qu'est-ce que clivoa, un framework pour le traitement ETL?
[Unix] Qu'est-ce que le processus zombie / processus orphelin?
Différence entre @classmethod et @staticmethod en Python
Quelle est la cause de l'erreur suivante?
Différence entre append et + = dans la liste Python
Différence entre non local et global en Python
Différence entre la régression linéaire, la régression Ridge et la régression Lasso
Qu'est-ce que "mahjong" dans la bibliothèque Python? ??
[Python] Différence entre la méthode de classe et la méthode statique
Différence entre le fichier env_file docker-compose et le fichier .env
La relation subtile entre Gentoo et pip
À propos de la relation entre Git et GitHub