Je développe un programme C++ et il serait utile d’utiliser une fonction, un script ou quelque chose qui fait redémarrer le programme. C'est un gros programme, donc redémarrer toutes les variables manuellement me prendra longtemps ...
Je ne sais pas s'il existe un moyen d'y parvenir ou si c'est possible.
Si vous avez vraiment besoin de redémarrer tout le programme (c'est-à-dire "fermer" et "ouvrir" à nouveau), la "bonne" méthode serait d'avoir un programme séparé dans le seul but de redémarrer votre programme principal. Autant que je sache, de nombreuses applications dotées de la fonction de mise à jour automatique fonctionnent de cette manière. Ainsi, lorsque vous devez redémarrer votre programme principal, vous appelez simplement le "redémarrage", puis quittez.
Vous pouvez utiliser une boucle dans votre fonction main
:
int main()
{
while(!i_want_to_exit_now) {
// code
}
}
Ou, si vous voulez réellement redémarrer le programme, lancez-le à partir d'un harnais:
program "$@"
while [ $? -e 42 ]; do
program "$@"
done
où 42
est un code de retour qui signifie "redémarrer, s'il vous plaît".
Ensuite, dans le programme, votre fonction restart
ressemblerait à ceci:
void restart() {
std::exit(42);
}
Sur Unicies ou ailleurs, vous avez execve
et cela fonctionne comme la page de manuel spécifie , vous pouvez simplement ...tue-moi pour avoir utilisé atoi
, parce que c'est généralement horrible, sauf pour ce genre de cas.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char** argv) {
(void) argc;
printf("arg: %s\n", argv[1]);
int count = atoi(argv[1]);
if ( getchar() == 'y' ) {
++count;
char buf[20];
sprintf(buf, "%d", count);
char* newargv[3];
newargv[0] = argv[0];
newargv[1] = buf;
newargv[2] = NULL;
execve(argv[0], newargv, NULL);
}
return count;
}
Exemple:
$ ./res 1
arg: 1
y
arg: 2
y
arg: 3
y
arg: 4
y
arg: 5
y
arg: 6
y
arg: 7
n
7 | $
(7 était le code de retour).
Il ne réclame ni ne fait explicitement de boucles. Au lieu de cela, il s’appelle simplement lui-même, en remplaçant son propre espace mémoire par une nouvelle version.
De cette manière, la pile ne débordera jamais, bien que toutes les variables précédentes soient redéclarées, comme pour toute réinvocation: l'appel getchar
empêche l'utilisation du processeur à 100%.
Dans le cas d’un binaire à mise à jour automatique, puisque le binaire complet (du moins sous Unix, je ne connais pas Windows) sera copié en mémoire au moment de l’exécution, puis si le fichier change sur le disque avant le execve(argv[0], ...
appel, le nouveau fichier binaire trouvé sur le disque, pas le même ancien, sera exécuté à la place.
Comme @CarstenS et @bishop l’indiquent dans les commentaires, en raison de la conception unique d’Unix, les descripteurs de fichiers ouverts sont conservés sur fork
/exec
, et Pour éviter les fuites des descripteurs de fichiers ouverts lors des appels à execve
, vous devez les fermer avant execve
ou les ouvrir avec e
, FD_CLOEXEC
/O_CLOEXEC
_ en premier lieu - plus d'informations peuvent être trouvées sur blog de Dan Walsh .
C'est une question très spécifique à l'OS. Sous Windows, vous pouvez utiliser = Application Restart API ou MFC Restart Manager . Sous Linux, vous pouvez faire un exec()
Cependant, la plupart du temps, il existe une meilleure solution. Vous feriez probablement mieux d'utiliser une boucle, comme suggéré dans d'autres réponses.
Cela ressemble à une mauvaise approche, car tout votre état est global et la seule méthode claire que vous ayez pour tout réinitialiser (autre que d'affecter manuellement des valeurs "par défaut" à chaque variable) consiste à redémarrer l'ensemble du programme.
Au lieu de cela, votre état devrait être contenu dans des objets (de type classe ou autre). Vous êtes alors libre de créer et de détruire ces objets quand vous le souhaitez. Chaque nouvel objet a un nouvel état avec des valeurs "par défaut".
Ne combattez pas C++; utilise le!
Vous avez probablement besoin d'une boucle:
int main()
{
while (true)
{
//.... Program....
}
}
Chaque fois que vous devez redémarrer, appelez continue;
dans la boucle et pour terminer votre programme, utilisez break;
.
Lorsque je développe des systèmes en temps réel, mon approche est normalement un "dérivé dérivé ()" où j'écris tout le code appelé à partir d'un réel principal (), quelque chose comme:
Le programme main.cpp:
int main (int argc, char *argv[])
{
while (true)
{
if (programMain(argc, argv) == 1)
break;
}
}
Le programmain.cpp, où tout le code est écrit:
int programMain(int argc, char *argv[])
{
// Do whatever - the main logic goes here
// When you need to restart the program, call
return 0;
// When you need to exit the program, call
return 1;
}
De cette manière, chaque fois que nous décidons de quitter le programme, le programme sera redémarré.
Détail: toutes les variables, les globales et la logique doivent être écrits à l'intérieur de programMain()
- rien à l'intérieur de "main()"
à l'exception du contrôle de redémarrage.
Cette approche fonctionne à la fois sur les systèmes Linux et Windows.
Il me semble que vous posez la mauvaise question parce que vous n'en savez pas assez sur le codage pour poser la bonne question.
Ce que vous demandez, c’est que vous demandez comment écrire un code qui, lors d’un appel manqué, revient en boucle à l’état initial et redémarre toute la séquence appel/emplacement. Dans ce cas, vous devez utiliser un machine à états . Cherchez ce que c'est et comment en écrire un. Ceci est un concept logiciel clé, et vous devriez le savoir si vos professeurs étaient bons dans leur travail.
En passant, si votre programme prend 5 secondes pour initialiser toutes vos variables, il faudra quand même prendre 5 secondes lorsque vous le redémarrez. Vous ne pouvez pas raccourcir cela. Donc, à partir de cela, il devrait être clair que vous ne pas voulez réellement tuer et redémarrer votre programme, car alors vous obtiendrez exactement le comportement que vous ne voulez pas. Avec une machine à états, vous pouvez avoir un état d'initialisation pour le démarrage à froid où le système vient juste d'être activé et un second état d'initialisation pour un redémarrage à chaud.
Oh, et 6 fils n'est pas très nombreux! :)
Selon ce que vous entendez par "redémarrer" le programme, je peux voir quelques solutions simples.
L'une consiste à intégrer votre programme entier dans une classe "Programme", qui fournit essentiellement une boucle contenant votre programme approprié. Lorsque vous devez redémarrer le programme, vous appelez la méthode publique statique "Redémarrer" qui relance la boucle.
Vous pouvez également essayer de faire un appel spécifique au système qui redémarre votre programme et quitte. Comme suggéré dans une autre réponse, vous pouvez créer un programme d'emballage à cette seule fin (et vérifier le code de retour pour savoir s'il faut quitter ou redémarrer).
L'autre option simple consiste à utiliser goto
. Je sais que les gens vont me haïr de le mentionner même, mais avouons-le: nous voulons faire un programme simple, pas utiliser un beau passe-partout. Goto aller garantit la destruction , vous pouvez donc créer un programme avec une étiquette au début et une fonction "Redémarrer" qui ne fait que remonter au début.
Quelle que soit l'option que vous choisissez, documentez-la bien afin que d'autres (ou vous-même à l'avenir) utilisent une WTF de moins.
PS Comme mentionné par alain , goto
ne détruira ni les objets globaux ni les objets statiques, il en irait de même pour la classe englobante. Par conséquent, toute approche n'incluant pas le démarrage d'un nouveau programme à la place du programme actuel doit s'abstenir d'utiliser des variables globales/statiques ou prendre les mesures appropriées pour les rétablir (bien que cela puisse être fastidieux, comme l'ajout de chaque variable statique/globale). , vous devez modifier la routine de redémarrage).