Quels sont les compromis pour “attente chargée” vs “sumil”?

Ceci est dans le prolongement de ma question précédente

Comment fonctionne le mode de blocage dans les sockets Unix / Linux?

Ce que je rassemble à partir d’Internet maintenant, tout le processus invoquant des appels bloquants, est mis en veille jusqu’à ce que le planificateur trouve les raisons de le débloquer. Les raisons peuvent varier d’un tampon vide à un tampon complet pour toute autre condition.

Mais alors, est-ce que cela peut être un moyen efficace de faire du temps réel, disons des applications temps-réel / fermes? Comme le processus n’est pas débloqué lorsque la condition de déblocage est vraie, plutôt lorsque le planificateur lui atsortingbue sa part de processeur et que la condition de déblocage est vraie à la fois.

Comme si vous vouliez une solution réactive, je ne pense pas que les “verrous tournants” ou les “attentes occupées” soient la bonne façon de procéder, les tranches de processeur sont gaspillées et, globalement, le système ne répond plus ou peut ne pas répondre.

Quelqu’un peut-il s’il vous plaît effacer ces pensées contradictoires.

Aller dormir jusqu’à ce que le programmateur vous réveille est la chose normale / préférée à faire.

La rotation (la manière alternative d’attendre, sans dormir) est moins courante et a les effets suivants:

  • Maintient le processeur occupé et empêche les autres threads d’utiliser le processeur (jusqu’à ce que le thread en cours d’exécution termine sa tranche de temps et qu’il soit prédéfini)

  • Vous pouvez arrêter de tourner à l’instant même où la chose que vous attendez arrive (parce que vous êtes continuellement à la recherche de cet événement et que vous n’avez pas besoin de prendre le temps de vous réveiller, parce que vous êtes déjà réveillé)

  • N’invoque pas les instructions du processeur nécessaires pour se mettre en veille et se réveiller

Spinning peut être plus efficace (moins de CPU total) que de s’endormir, si la durée du délai est très courte (par exemple si le délai est limité à l’exécution des 100 instructions de la CPU).

Un Spin Lock grave le processeur et le chemin d’access aux ressources interrogées pour un gaspillage continu de ressources lorsque l’événement souhaité ne se produit pas.

Une opération de blocage diffère surtout en laissant le processeur et le chemin de ressource associé et en installant une wait sur la ressource à partir de laquelle l’événement souhaité est attendu.

Dans un environnement multitâche ou multithread / processeur (le cas habituel depuis longtemps), lorsque d’autres opérations sont possibles alors que l’événement souhaité n’est pas arrivé, la gravure des chemins d’access des ressources et des ressources entraîne une perte de temps et de traitement.

Lorsque nous avons un système hyperthreading (comme vous le pensez dans votre question, par exemple), il est important de noter que la granularité des tranches de processeurs est très élevée. Je tiens à faire remarquer que tous les événements – sur lesquels vous avez tendance à bloquer – prendraient suffisamment de temps pour compenser la petite tranche de temps pour laquelle ils devaient attendre avant de débloquer.


Je pense que le point J-16 est vers la condition où un thread en sumil (bloqué) laisse son code et son espace de données inutilisés en état bloqué. Cela pourrait faire en sorte qu’un système renonce à des ressources (telles que des caches de données / codes), qui devraient ensuite être remplies lorsque le bloc est libéré. Par conséquent, sous réserve de certaines conditions, un bloc peut entraîner un gaspillage de ressources plus important.
Ceci est également une note valide et doit être vérifié lors de la conception et de la mise en œuvre.
Mais le blocage est généralement meilleur que le blocage de spin dans la plupart des conditions.

Si, dans le cas d’utilisation de votre application, le changement de contexte serait plus coûteux que de consumr peu de cycles du processeur, votre condition serait garantie d’être satisfaite rapidement, alors que l’attente occupée pourrait vous être bénéfique.

Sinon, vous pouvez renoncer de force au processeur en dormant ou en cond_wait() ing.

Un autre scénario auquel je peux penser pour changer de contexte de force est le suivant:

 while(condition) sleep(0); 

Tout d’abord, vous avez une idée fausse:

Les appels bloquants ne sont pas “en attente” ou “tournent les verrous”. Les appels bloquants sont dormables – cela signifie que le processeur fonctionnera sur d’autres tâches, aucun processeur n’est gaspillé.

Sur votre question sur le blocage des appels

Les appels bloquants sont plus faciles – ils sont faciles à comprendre, plus faciles à développer et plus faciles à déboguer.

Mais ils sont des porcs de ressources. Si vous n’utilisez pas le thread, cela bloquerait d’autres clients; Si vous utilisez un thread, chaque thread utilisera de la mémoire et d’autres ressources système. Même si vous avez beaucoup de mémoire, changer de fil rend le cache froid et réduit les performances.

Ceci est un compromis – développement plus rapide et maintenabilité? ou évolutivité.

Je vais essayer d’être au point car suffisamment d’explications sont fournies ici par d’autres réponses et oui, en apprenant de toutes ces réponses, je pense qu’une image complète sera. —

Selon moi, le compromis entre la réactivité et le débit du système.

Réactivité – peut être considéré sous deux angles

  • sur toute la réactivité du système, et
  • une réactivité particulière ou par processus

Je pense que pour la réactivité du système , le blocage des appels est la meilleure solution. Comme il donne le processeur à l’autre processus dans la queue, lorsque l’appel de blocage à l’état bloqué.

Et bien sûr, pour un processus particulier ou une réactivité par processus , nous considérerons un modèle occupé-wait / spin-lock.

Maintenant, encore une fois, pour augmenter la réactivité globale du système, nous ne pouvons pas diminuer la tranche de temps (grain fin) pour le planificateur, car cela gaspillerait trop de ressources CPU dans le changement de contexte. Et donc le débit du système diminuerait considérablement. Bien entendu, il est évident que le modèle de blocage augmente le débit du système, car les appels bloqués ne consumnt pas de tranches de processeur et le transmettent à l’autre processus suivant dans la queue.

Je pense que le meilleur à faire est de concevoir un système avec une réactivité par processus en tête, sans affecter la réactivité globale et le débit grâce à l’implémentation d’un planificateur basé sur les priorités, avec des considérations sur les problèmes d’inversion prioritaires. vous dérange 🙂

// Code source original ASPI adapté …

  DWORD startStopUnit (HANDLE handle, BOOL bLoEj, BOOL bStart) { DWORD dwStatus; HANDLE heventSRB; SRB_ExecSCSICmd s; //here heventSRB = CreateEvent (NULL, TRUE, FALSE, NULL); memset (&s, 0, sizeof (s)); s.SRB_Cmd = SC_EXEC_SCSI_CMD; s.SRB_HaID = 0; s.SRB_Target = 0; s.SRB_Lun = 0; s.SRB_Flags = SRB_EVENT_NOTIFY; s.SRB_SenseLen = SENSE_LEN; s.SRB_CDBLen = 6; s.SRB_PostProc = (LPVOID) heventSRB; s.CDBByte[0] = 0x1B; s.CDBByte[4] |= bLoEj ? 0x02 : 0x00; s.CDBByte[4] |= bStart ? 0x01 : 0x00; ResetEvent (heventSRB); dwStatus = SPTISendASPI32Command (handle,(LPSRB) & s); if (dwStatus == SS_PENDING) { //and here, don´t know a better way to wait for something to finish without processor cicles WaitForSingleObject (heventSRB, DEFWAITLEN); } CloseHandle (heventSRB); if (s.SRB_Status != SS_COMP) { printf("Erro\n"); return SS_ERR; } printf("nao Erro\n"); return s.SRB_Status; }