LoriotPro Extended Edition Programmation en language LUA

Table des matières

HelpLUA

Unité d'éxécution (Threads)


Fils de préemption et Lua

La norme ANSI C, la norme à laquelle Lua se conforme, n'a aucun mécanisme pour contrôler les fils multiples de l'exécution. Des fils et les objets de synchronisation employés pour les commander sont fournis par le logiciel d'exploitation fondamental. Vous devrez employer ces derniers afin de mettre en application le filetage dans Lua. Vous n'aurez pas besoin de modifier la distribution de Lua pour faire ceci.

Les fils sont rusés pour devenir exacts même dans le plus simple des circonstances telles qu'une application pure de C. Une application qui enfonce ou prolonge Lua doit faire face à la complexité additionnelle des fils coordonnés avec la bibliothèque de Lua. Si vos besoins de traitement multitâche peuvent être rencontrés les coroutines simple-filetés de Lua, vous bien-seriez conseillé de choisir cet itinéraire. Lisez CoroutinesTutorial pour plus de détails. Si vous choisissez de mettre en application les fils de préemption multiples à votre Lua projettent, les directives suivantes peuvent aider.

Chaque fil en C qui agit l'un sur l'autre avec Lua aura besoin de son propre état de Lua. Chacun de ces états a sa propre pile d'exécution. Quand un nouveau fil de C est commencé, vous pouvez créer son état de Lua dans une de deux manières. L'one-way doit appeler lua_open. Ceci crée un nouvel état qui est indépendant des états en d'autres fils. Dans ce cas-ci, vous devrez initialiser l'état de Lua (par exemple, bibliothèques de programmes) comme si c'était l'état d'un nouveau programme. Cette approche élimine le besoin de serrures de mutex (discutées ci-dessous), mais gardera les fils de partager des données globales.

L'autre approche est d'appeler lua_newthread. Ceci crée un état d'enfant qui a sa propre pile et qui a accès aux données globales. Cette approche est discutée ici.

Fermeture par Lua

Votre plus grand souci quand travailler avec des fils doit les empêcher de corrompre les environnements de chacun. Les problèmes subtiles ou non-ainsi-subtiles, immédiats ou parfois de façon exaspérante retardés, attendent un fil qui revient après le droit de préemption à un environnement qui a été laissé dans un état inattendu par un autre fil. Cependant, vous voulez généralement que les fils partagent certaines structures de données, aussi. C'est où les objets de mutex du logiciel d'exploitation héritent le jeu. Un objet de ce type peut être fermé à clef par pas plus d'un fil à la fois.

Avec de l'aide de vous, Lua empêchera ses structures de données internes d'être corrompue. Quand Lua entre dans une opération qui ne doit pas être appropriée, elle appelle lua_lock. Quand l'opération critique est complète, elle appelle lua_unlock. Dans la distribution de défaut ces deux fonctions ne font rien. Quand employer filète dans Lua, elles devraient être remplacées avec des réalisations OS-DÉPENDANTES. Dans un environnement de POSIX vous emploierez un objet de type pthread_mutex_t. Dans Windows, vous emploierez l'un ou l'autre une poignée dont est retourné CreateMutex, ou, plus de façon optimale, une structure de données opaque de type CRITICAL_SECTION.

Tous les coroutines dans un univers particulier de lua doivent partager le même mutex. Évitez l'erreur d'associer le mutex à un état spécifique de Lua et puis ne la trouvent pas encore quand un coroutine différent dans le même univers est verrouillé. Un exemple simple pour Win32 suit. Le dossier d'en-tête luauser.h contient :


  # définissez le lua_lock(L) LuaLock(L) # définissent le 
lua_unlock(L) LuaUnlock(L) # définissent le lua_userstateopen(L) 
LuaLockInitial(L) # définissent le lua_userstatethread(L, L1) 
LuaLockInitial(L1)// Lua 5.1 LuaLockInitial(lua_State vide * L) ; 
videz LuaLockFinal(lua_State * L) ; videz 
LuaLock(lua_State * L) ; videz LuaUnlock(lua_State * L) ;

Les trois définitions de préprocesseur seront employées quand Lua est compilé. En date de la version 5.0.2, Lua regrettablement ne fournit pas un appel pour détruire une serrure.

La fonction lua_userstateopen s'appellera toutes les fois qu'un nouvel état de Lua est créé, à si avec un appel lua_open ou lua_newthread. Il est important que le mutex soit créé seulement la première fois lua_userstateopen s'appelle.

Dans Lua 5.1 luai_userstatethread(L,L1) est réclamés des fils créés avec lua_newthread. et luai_userstateopen(L) est réclamé des états de lua créés près lua_newstate (mais pas près lua_newthread). luai_userstateclose(L) est réclamé des fils fermés près lua_close seulement.

Le dossier associé de C luauser.c, contient :


  # incluez < windows.h > # incluent "lua.h" # incluent le 
struct statique de "luauser.h" {CRITICAL_SECTION LockSct ; BOOL 
Init ; } Gl ; LuaLockInitial(lua_State vide * L) {si (! 
Gl.Ilente) {/* créez * de 
mutex/InitializeCriticalSection(&Gl.LockSct) ; Gl.Ilente = 
RECTIFIENT ; }} LuaLockFinal(lua_State vide * L)/* non appelé 
par Lua. */{/* détruisez un mutex. */si (Gl.Ilente) 
{DeleteCriticalSection(&Gl.LockSct) ; Gl.Ilente = FAUX ; 
}} LuaLock(lua_State vide * L) {/* attente la commande du * de 
mutex/EnterCriticalSection(&Gl.LockSct) ; } LuaUnlock(lua_State 
vide * L) {/* contrôle de la diffusion du * de 
mutex/LeaveCriticalSection(&Gl.LockSct) ; }

Ces deux dossiers n'ont pas besoin de résider dans l'arbre de distribution de Lua, mais ils doivent être accessibles pendant la construction. En plus, vous devrez définir LUA_USER_H de sorte que votre incluiez le dossier soit employé par Lua. Les citations doivent faire partie de la définition, de sorte qu'une expression quelque chose aiment


  /DLUA_USER_H="""luauser.h" ""

devra être transporté au compilateur. En outre, vous pouvez devoir prolonger le chemin d'inclusion de sorte que le compilateur puisse trouver votre dossier.

Fermeture par l'application

Lua empêche ses structures de données internes de devenir corrompues au moyen des fonctions de fermeture. Il appartient à l'application pour empêcher des problèmes avec les structures de données exposées, s'ils sont globaux ou des upvalues. Un mutex peut être employé pour coordonner l'utilisation de ressource employant des fonctions comme celles montrent en haut. Cependant, soyez sûr d'employer un mutex différent que celui employé par Lua afin d'éviter des impasses potentielles.

En concevant des applications multi-filetées, il est utile de prêter une attention particulière à où chaque fil attend. Rendiez-vous toujours compte que des opérations sans surveillance peuvent être interrompues. Si n'importe quel autre fil pourrait être compromis par l'état dans lequel une interruption se produit, une certaine forme d'exclusion mutuelle s'appelle pour.

Mutex et multitraitement globaux

La méthode ci-dessus pour mettre en application le filetage dans Lua employant un mutex global est inefficace sur des systèmes de multiprocesseur. Car un fil tient le mutex global, d'autres fils l'attendent. De ce fait seulement un fil de Lua peut fonctionner à la fois, indépendamment du nombre de processeurs dans le système.

Sur quelques systèmes il pourrait être nécessaire de rapporter le fil après avoir ouvert le mutex, afin d'empêcher le même fil de le fermer à clef encore, au cas où il y aurait d'autres qui attendent là-dessus. Ceci se produit au moins sur Linux en utilisant Boost.Threads. Le dépassement luai_threadyield (qui par des appels de défaut lua_unlock, suivis immédiatement près lua_lock) pour rapporter le fil inbetween la serrure et l'ouvrir est probablement une bonne idée. Cependant, le luai_threadyield s'appelle par le macro de dojump dans la machine virtuelle, par conséquent un rendement à chaque appel de luai_threadyield pourrait considérablement dégrader l'exécution. L'alternative suivante pourrait être utile :

lua_State vide de luai_threadyield(struct * L) {count=0 
interne statique ; y=false de bool ; si (compte -- <=0) 
{y=true ; count=30 ; } ; //valeurs d'essai 
différentes au lieu du lua_unlock(L) 30. ; si (y) 
thread::yield() ; lua_lock(L) ; }


LUTEUS www.loriotpro.com