[JAVA] Bibliothèque Kinx - Processus

Bibliothèque Kinx - Processus

introduction

** "Ressemble à JavaScript, le cerveau (contenu) est Ruby, (la stabilité est AC / DC)" ** Langage de script Kinx ). La langue est la bibliothèque. Alors, comment utiliser la bibliothèque.

Cette fois, c'est Process. Je l'ai fait à la hâte car il était nécessaire de démarrer un processus enfant.

System.exec()

Une interface d'exécution de commandes préparée en standard depuis longtemps. C'est facile parce que vous appelez simplement system () au niveau C, mais c'est gênant car il ne revient pas tant qu'il n'est pas terminé, ou vous ne pouvez pas obtenir la sortie standard. Cependant, puisque la commande est exécutée via le shell, des redirections peuvent être utilisées.

Donc, cette fois, j'ai créé une classe Process qui peut faire plus de choses, c'est donc le favori dans cette explication.

Process

using Process

La bibliothèque Process n'est pas intégrée, utilisez donc la directive using pour la charger explicitement.

using Process;

Exec

L'objet Process est créé avec new Process (command, opts). L'argument est un nom de commande et un tableau d'arguments, ou une chaîne de commande. Dans le cas d'un tableau, on a l'impression de passer les arguments séparément, et dans le cas d'une chaîne de ligne de commande, il est analysé en interne et automatiquement décomposé en un format tableau.

L'objet de processus créé a les méthodes suivantes.

Méthode Aperçu
run() Démarrez le processus.
launch() Démarrez le processus et déconnectez-vous.
std() Les options passées en arguments sont renvoyées.
{ in: opts.in, out: opts.out, err: opts.err }

Pas encore en cours d'exécution à ce stade. Il démarre lorsque run () ou launch () est exécuté. run () renvoie un objet de la classe ProcessController.

Run

run () renvoie un objet de la classe ProcessController.

var p = new Process(["cmd","arg1"]).run();

Launch

launch () ne renvoie rien (ou plutôt null). La méthode consiste à ne pas prendre soin de l'enfant après l'avoir poussé.

new Process(["cmd","arg1"]).launch();

ProcessController

La classe ProcessController retournée par run () a les méthodes suivantes.

Méthode Aperçu
isAlive() Vrai si le processus est actif, s'il est déjà terminé, oudetachFaux après avoir été fait
wait() Attend la fin du processus et renvoie le code de fin du processus après la fin.detachPuis renvoie 0.
detach() Détachez le processus

detach () est déconnecté après le démarrage du processus. Sous Linux, le fonctionnement est légèrement différent du cas de la déconnexion avec launch (), mais ce que vous voulez faire est le même. Le fonctionnement interne est le même sous Windows.

Sous Linux, la méthode dite ** double-fork ** est utilisée pour se déconnecter lorsque le processus est lancé, mais elle ne peut être utilisée que lorsque le processus est lancé. Il est pratiquement impossible de se déconnecter après avoir démarré un processus, et si le processus parent n'attend pas ou n'attend pas correctement, l'enfant survivra en tant que zombie.

Donc, au moment de detach (), je lance un thread juste pour waitpid et je m'en occupe jusqu'à ce que l'enfant meure.

Au fait, le double-fork est Linux,

En utilisant la fonction appelée ..., vous pouvez forker le processus qui était autrefois forké, puis terminer le premier processus forké à la hâte et laisser init gérer le processus petit-fils.

Le processus parent supérieur se souvient du waitpid du premier enfant forké. Mon petit-fils est celui qui prend soin de moi.

Wait

Voici un exemple d'attente de la fin et d'obtention du code de fin.

var p = new Process(["cmd", "arg1"]).run();
var status = p.wait();

Bien sûr, si vous avez detach, vous ne pouvez pas l'obtenir (0 est retourné).

Detach

Le «détachement» qui est sorti plus tôt. Le processus peut également être "détaché". Si vous le séparez, la connexion avec l'enfant sera coupée. Vous n'avez pas à attendre et vous n'avez pas à vous soucier de la fin. Ou plutôt, vous ne pouvez pas le faire même si vous voulez vous en soucier.

var p = new Process(["cmd", "arg1"]).run();
p.detach();

Pipe

J'attends la pipe. Le but principal de la création de «Process» est le pipe. La fonction la plus souhaitée est de connecter librement l'entrée / sortie standard au processus enfant à un tube pour échanger des informations.

Le tube est spécifié par ʻoptsdenew Process (cmd, opts)`. Il existe trois types de paramètres comme suit.

Paramètres Contenu
in Spécifiez l'entrée standard.
Vous pouvez spécifier un objet pipe, une chaîne,$stdin
out Spécifiez la sortie standard.
Vous pouvez spécifier un objet pipe, une chaîne,$stdoutOu$stderr
err Spécifiez la sortie d'erreur standard.
Vous pouvez spécifier un objet pipe, une chaîne,$stdoutOu$stderr

Objet Pipe

Les objets Pipe sont créés avec «new Pipe ()». Renvoie un tableau de deux objets, [Read, Write], par paires. L'objet pipe a les méthodes suivantes.

Normalement, le tube Write est spécifié comme ʻout ou ʻerr du processus enfant et lu depuis le tube Read.

Read Pipe

Fermez le tube après run (). Parce qu'il est défini lorsque run () est terminé.

Méthode
peek() Renvoie 0 s'il n'y a pas de données dans le tube, supérieur à 0 s'il y en a.-1 est une erreur.
read() Obtenez toutes les données de canal sous forme de chaîne. S'il n'y a pas de données, une chaîne de caractères vide est renvoyée.
close() Fermez le tuyau.

Write Pipe

Fermez le tube après run (). Parce qu'il est défini lorsque run () est terminé.

Méthode
write(data) Écrivez des données dans le tuyau. Tout ne peut pas être écrit et le nombre d'octets écrits est renvoyé.
close() Fermez le tuyau.
échantillon

La forme générale est utilisée comme suit.

using Process;

var [r1, w1] = new Pipe();
var p1 = new Process([ "ls", "-1" ], { out: w1 }).run();
w1.close(); //Je ne l'utilise plus pour que tu puisses le fermer
while (p1.isAlive() || r1.peek() > 0) {
    var buf = r1.read();
    if (buf.length() < 0) {
        System.println("Error...");
        return -1;
    } else if (buf.length() > 0) {
        System.print(buf);
    } else {
        // System.println("no input...");
    }
}
System.println("");

Lorsque vous utilisez Write Pipe du côté du processus parent, cela ressemble à ceci.

using Process;

//stdin lit le tube et les sorties vers la sortie standard
[r1, w1] = new Pipe();
var p1 = new Process("cat", { in: r1, out: $stdout }).run();
r1.close(); //Je ne l'utilise plus pour que tu puisses le fermer

//Envoyer à stdin sur p1
var nwrite = w1.write("Message\n");
w1.close(); //Fermeture de tuyau, extrémité de transmission

p1.wait();

En passant, cela vous permet de contrôler la sortie standard et la sortie d'erreur standard.

new Process("cmd", { out: $stdout, err: $stdout }); //Fusionner la sortie d'erreur standard avec la sortie standard
new Process("cmd", { out: $stderr, err: $stderr }); //Fusionner la sortie standard avec la sortie d'erreur standard
new Process("cmd", { out: $stderr, err: $stdout }); //Échanger

Pipeline

Connecter des tuyaux est une tâche assez fastidieuse (ou plutôt, laquelle est ...?), J'ai donc également défini Process.pipeline, qui fait tout en même temps. Enfin, mettez une fonction de rappel et utilisez-la comme suit.

var r = Process.pipeline(cmd1, cmd2, cmd3, ..., &(i, o, pipeline) => {
    // i ...Ecrire le tube vers stdin pour la première commande
    // o ...Lire le tube depuis la sortie standard de la dernière commande
    // pipeline ...Objet Pipeline
    //    pipeline.input .......Identique à i ci-dessus
    //    pipeline.output ......Identique à o ci-dessus
    //    pipeline.peek() ...... pipeline.output.peek()Pareil que
    //    pipeline.read() ...... pipeline.output.read()Pareil que
    //    pipeline.write() ..... pipeline.input.write()Pareil que
    //    pipeline.isAlive() ...Vrai si un processus du pipeline est actif
    //    pipeline.wait() ......Attendez que tous les processus du pipeline se terminent,
    //Renvoie le code de fin sous forme de tableau

    //La valeur de retour du rappel reste telle qu'elle est Process.pipeline()Il devient la valeur de retour de.
    return pipeline.wait();
});

Vous pouvez l'utiliser sans rappeler.

var pipeline = Process.pipeline(cmd1, cmd2, cmd3, ...);
// pipeline ...Objet Pipeline
//Omis ci-dessous.

en conclusion

La relation de processus enfant est différente entre Windows et Linux, c'est donc un bon point du script pour pouvoir gérer de telles choses de manière unifiée. Cependant, les commandes elles-mêmes sont différentes, il est donc difficile de les absorber. Je suis un utilisateur Windows, mais j'utilise UnxUtils pour rendre certaines commandes Unix disponibles à l'invite de commande également. (Je n'aime pas vraiment Cygwin car cela change l'environnement ...)

Alors la prochaine fois.

Recommended Posts

Bibliothèque Kinx - Processus
Bibliothèque Kinx --Obtenir
Bibliothèque de compilateur Kinx Library-JIT
Bibliothèque de compilateur Kinx Library-JIT (édition supplémentaire)