Les fibers : des threads non preemptables

LES FIBERS : DES THREADS NON PREEMPTABLES

PLAN :

RAPPELS

LES FIBERS

MODE D’EMPLOI

FIBERS ET DELPHI

CONCLUSION

RAPPELS (un peu de théorie).

L’utilisation des Threads en programmation est assez répandu et apporte de grands services quand il s’agit de produire un programme multitâche.

Un Thread est une entité d’exécution représentant un flux d’exécution indépendant mais appartenant à un processus principal. Toute application Win32 est donc constituée au minimum d’un Thread appelé Thread principal, Thread primaire ou Thread par défaut. A partir de ce Thread principal, vous pouvez faire démarrer autant de Threads secondaires que nécessaire.

Ces Threads permettent de donner l’impression que plusieurs tâches s’exécutent en parallèle. En fait, sauf si vous avez un ordinateur multicore, ces Threads ne s’exécutent pas en parallèles. Chacun reçoit tour à tour une tranche de temps lui permettant d’utiliser le processeur (quelques milliers de cycles processeur à la fois). C’est le système d’exploitation qui joue ce rôle d’arbitrage. Et c’est plutôt un rôle tyrannique dans la mesure où vous ne disposez que de très peu de moyens d’influencer le cours de l’application. Il y a, à ma connaissance, trois moyens d’avoir un peu d’influence sur la tyrannie du système :

  • les priorités des Threads qui sont bien connues mais que je trouve peu efficaces et parfois dangereux
  • le fait de suspendre purement et simplement un Thread (MonThread..Suspend)
  • un moyen un peu moins connu qui permet de donner immédiatement la main au Thread suivant : c’est un simple Sleep() dans le code du Thread à interrompre (Sleep sans paramètre).

Le fait que tous les Threads soient interrompus absolument à n’importe quel moment nous oblige à prendre d’infinies précautions quand il s’agit de communiquer entre eux ou avec le Thread principal, mais c’est une autre histoire…

LES FIBERS

C’est ici qu’interviennent les Fibers.

Les fibers sont des sortes de Threads dont vous conservez le contrôle d’exécution.

Imaginez une animation composée de Sprites interdépendants ou alors une tâche qui consiste à faire des tris dans différents fichiers, de les fusionner, supprimer, etc…

Vous trouverez sans doute pratique de pouvoir gérer vous-même la coopération et le séquençage des différents Threads. Vous le ferez à l’aide des Fibers.

Les Fibers sont des sous-Threads et y ressemblent donc beaucoup. Comme eux, ils permettent de gérer des informations de statut via un contexte d’exécution, une pile et un jeu de registres processeur indépendant. Par contre, les fibers ne peuvent pas être interrompus (préemptés) par le système. Ce sera donc à vous d’assurer manuellement le basculement entre un Fiber et un autre. L’avantage est que vous n’aurez pas à vous soucier de la synchronisation des Fibers.

MODE D’EMPLOI DES FIBERS

On part donc d’un Thread. Il sera créé au choix et selon l’application par :

  • CreateThread(), API Windows
  • BeginThread(), la traduction Delphi de l’API précédente
  • La classe TThread de Delphi, portable Windows/Linux

Je vous renvoie aux nombreux tutos qui traitent de ce sujet…

Il n’y a que 6 fonctions à connaître pour travailler avec les Fibers :

1) ConvertThreadToFiber()

2) CreateFiber()

3) SwitchToFiber()

4) GetCurrentFiber()

5) GetFiberData()

DeleteFiber()



Un Fiber doit donc s’exécuter dans le contexte d’un Thread. Un Thread peut donc héberger plusieurs Fibers qui partageront les temps d’exécution aloués au Thread initial. Ce Thread doit d’abord être converti en Fiber au moyen de la fonction :

Function ConvertThreadToFiber(lpParameter : Pointer) : POINTER ; stdcall ;

L’unique paramètre de cette fonction permet de transmettre des données spécifique au Fiber de la même manière que vous transmettez des données à un Thread avec BeginThread() ou CreateThread().

La fonction renvoie un pointeur vers un objet Fiber.

Une fois que le Thread a été converti en Fiber, vous pourrez créer d’autres Fibers issus de ce Thread avec l’API:

Function CreateFiber(dwStackSize : DWORD, lpStartAddress : LPFIBER_START_ROUTINE, lpParameter : Pointer ): POINTER; stdcall;

dwStackSize définit la taille initiale de la pile du Fiber (en octets). 0 pour utiliser la taille standard.

lpStartAddress définit l’adresse de la procédure que le Fiber doit commencer à exécuter dès le départ.

lpParameter contient des données spécifiques comme pour ConvertThreadToFiber().

La fonction renvoie un pointeur vers un objet Fiber.



Une fois vos Fibers créés, vous pouvez commencer à effectuer votre propre distribution du temps de traitement. Vous basculerez d’un Fiber à l’autre au moyen de la fonction :

Function SwitchToFiber(lpFiber : Pointer); stdcall ;

lpFiber est un pointeur vers un objet Fiber.

Le système d’exploitation gèrera tous les détails du basculement de contexte.

La fonction ne renvoie rien ( Moi, j’appelle ça une procédure. Mais bon ! ).

Pour connaître l’adresse du Fiber en cours d’exécution, il faut employer :

Function GetCurrentFiber

Il n’y a pas de paramètre et la fonction renvoie simplement l’adresse du Fiber qui est en cours.



Function GetFiberData renvoie les données associées au Fiber en cours. C’est la valeur passée à ConvertThreadToFiber() et à CreateFiber() dans le paramètre lpParameter.

Quand vous n’avez plus besoin d’un Fiber, il suffit de transmettre le pointeur de l’objet Fiber à détruire à la fonction :

Function DeleteFiber(lpFiber : Pointer); stdcall ;

Cette fonction ne renvoie rien.

ATTENTION ! Si vous appelez DeleteFiber() dans le Fiber en cours d’exécution, cela provoque un appel à ExitThread(), qui provoque lui-même la fin de la totalité du Thread. Sauf si c’est ce qui est recherché, il ne faut appeler DeleteFiber() qu’en transmettant un pointeur d’un Fiber différent du Fiber en cours afin de ne détruire que celui-là.

LES FIBERS SOUS DELPHI

Les ingénieurs de Borland n'ont jamais jugé utile d'intégrer les Fibers dans l'unité Windows. Je trouve que c'est dommage, mais c’est bien la preuve qu’on peut vivre sans les Fibers… comme on peut vivre sans chocolat ;)

Ceci dit, il y a peut-être des raisons que j’ignore encore. Mais la littérature sur les Fibers est si pauvre sur Internet qu’il n’est pas encore possible de se faire une opinion valable.

C’est d'autant plus regrettable qu'il ne faut que 6 routines pour travailler avec les Fibers et que c’est plus simple que les Threads. De plus, il est parfois intéressant de disposer de sortes de Threads qui ne peuvent pas être préemptés (interrompus) par le système d'exploitation à tous bouts de champ et n'importe quand...

C’est la raison pour laquelle je voulais vous faire partager mes maigres connaissances sur les Fibers et vous permettre de faire vos propres expériences en vous proposant une unité qui vous autorisera à passer outre au bridage de Delphi.

Vous trouverez cette petite démo à cette adresse :

http://www.delphifr.com/codes/FIBERS-THREADS-NON-PREEMPTES-SYSTEME_49393.aspx

CONCLUSION

Quelques liens :

Fibers : http://msdn.microsoft.com/en-us/library/ms682661(VS.85).aspx

Using Fibers : http://msdn.microsoft.com/en-us/library/ms686919(VS.85).aspx

Merci à Steve Teixera et Xavier Pacheco qui m’ont fait découvrir cette technique.

Ils sont les auteurs de DELPHI6

Chez CampusPress – collection Référence.

Merci à toi, lecteur de passage, en espérant ne pas t’avoir trop gonflé la fibre.

Adresse d'origine

A voir également
Ce document intitulé « Les fibers : des threads non preemptables » issu de CodeS SourceS (codes-sources.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.
Rejoignez-nous