C++: comment implémenter un délai d'attente pour un appel de fonction arbitraire?

J'ai besoin d'appeler une fonction de bibliothèque qui parfois ne se terminera pas dans un temps donné, malheureusement. Existe-t-il un moyen d'appeler la fonction mais de l'abandonner si elle ne se termine pas dans n secondes?

Je ne peux pas modifier la fonction, donc je ne peux pas y mettre directement la condition d'abandon. Je dois Ajouter un délai d'attente à la fonction en externe .

Est-ce peut-être une solution possible de le démarrer en tant que thread (boost), que je peux ensuite terminer après un certain temps? Serait quelque chose comme ce travail? Je crois en fait que la fonction est Pas thread-safe, mais cela n'aurait pas d'importance si je l'exécutais comme seulement thread unique, non? Existe-t-il d'autres (meilleures) solutions?

25
demandé sur Frank 2009-05-19 01:20:08

9 réponses

Vous pouvez générer un boost::thread pour appeler L'API:

boost::thread api_caller(::api_function, arg1, arg2);
if (api_caller.timed_join(boost::posix_time::milliseconds(500)))
{
    // API call returned within 500ms
}
else
{
    // API call timed out
}

Boost ne vous permet pas de tuer le thread de travail, cependant. Dans cet exemple, c'est juste orphelin.

Vous devrez faire attention à ce que cet appel D'API fait, car il peut ne jamais libérer les ressources qu'il a acquises.

18
répondu Ben Straub 2009-05-18 21:45:13

Je pense que le seul moyen sûr d'y parvenir serait de générer un processus sandbox distinct qui appelle la fonction de bibliothèque en tant que proxy à votre application. Vous devrez implémenter un type D'IPC entre votre application et le proxy. La mise en œuvre d'un délai d'attente lors de la lecture de la réponse IPC est alors assez triviale. Si la lecture échoue en raison du délai d'attente, vous pouvez alors résilier le proxy en toute sécurité sans risquer la santé de votre application.

15
répondu An̲̳̳drew 2009-05-21 14:36:49

Ce dont vous parlez est généralement appelé un système de" chien de garde". Le chien de garde est généralement un deuxième thread qui vérifie l'état de tous les autres threads. Le chien de garde est généralement configuré pour fonctionner périodiquement. Si aucune réponse n'a été reçue des autres threads, le chien de Garde peut avertir l'utilisateur, ou même tuer le thread incriminé s'il est possible de le faire en toute sécurité (dépend de votre application).

8
répondu Doug T. 2009-05-19 12:56:13

Le problème avec les threads est que certaines ressources que vous ne pourrez pas libérer après la fin du thread. Si vous n'acquérez pas de ressources que vous devez libérer, allez avec des threads.

3
répondu Mykola Golubyev 2009-05-18 21:25:34
3
répondu Bruno Martinez 2009-05-18 22:50:25

Le problème est qu'avec une solution en cours de processus sans support de la fonction vous vous retrouvez avec un état potentiellement invalide.

Exemple: lorsque vous terminez le thread pendant qu'une allocation de mémoire a lieu, votre tas de processus peut être corrompu.

Vous pouvez donc terminer l'appel, mais vous devez également terminer le processus. Dans de nombreux cas, les chances d'effets secondaires destructeurs sont faibles, mais je ne parierais pas mon calcul sur cela.

Vous pouvez, comme Ben Straub suggère, juste orphelin le fil: mettez-le sur la priorité la plus basse et laissez-le courir pour l'infini. Ce n'est bien sûr qu'une solution limitée: si le thread consomme des ressources (probablement), il ralentira le système, il y a aussi une limite sur les threads par processus (généralement en raison de l'espace d'adressage pour la pile de threads).

Généralement, je préférerais la solution de processus externe. Un modèle simple est le suivant:
Écrivez les données d'entrée dans un fichier, démarrez le processus externe avec le fichier comme argument. Le processus externe écrit la progression (le cas échéant) dans un fichier disque qui peut être surveillé, et peut même permettre au processus de reprendre à partir de l'endroit où il a commencé. Les résultats sont écrits sur le disque et le processus parent peut les lire.

Lorsque vous terminez le processus, vous devez toujours gérer la synchronisation de l'accès aux ressources externes (comme les fichiers), et comment gérer les mutices abandonnés, les fichiers à moitié écrits, etc. Mais c'est généralement le chemin vers une solution robuste.

3
répondu peterchen 2010-09-19 03:06:35

Ce dont vous avez besoin est un thread et un futur objet qui peut contenir le résultat de l'appel de fonction.

Pour un exemple d'utilisation de boost voir ici.

Vous devrez vérifier l'avenir après le délai d'attente et s'il n'est pas défini, agissez en conséquence.

1
répondu lothar 2009-05-18 21:59:45

Allez avec un processus orphelin, lancez-le et chronométrez son exécution. S'il manque de temps, invoquez le système d'exploitation pour le tuer.

Comment éviter les conds de course. sur ce modèle:

  • Créez un fichier à stocker dans args (bien sûr, tout est transmis en tant que VALs). Le processus orphelin est uniquement autorisé à lire les données de ce fichier.

  • L'orphelin traite les données d'entrée, crée un fichier de sortie avec des valeurs de résultat et le ferme.

  • Seulement quand tout est terminé, orphan supprime le fichier d'entrée, un fait qui signale au processus maître que le travail a été effectué.

Cela évite de lire le problème des fichiers à moitié écrits, puisque le maître remarque d'abord l'absence du fichier d'entrée, ouvre pour lire le fichier de sortie, qui est sûrement terminé (car il a été fermé avant la suppression de l'entrée, et les piles D'appels du système d'exploitation sont séquentielles).

1
répondu jpinto3912 2009-05-21 21:34:46

" j'ai besoin d'appeler une fonction de bibliothèque qui parfois ne se terminera pas dans un temps donné, malheureusement. Existe-t-il un moyen d'appeler la fonction mais de l'abandonner si elle ne se termine pas dans les n secondes?"

La réponse courte est non. C'est généralement des problèmes... L'appel lui-même doit se terminer à un moment donné (implémentant son propre timeout), mais les appels bloquants sont généralement des problèmes (par exemple gethostbyname()) parce que c'est à leur (ou système) timeout, pas le vôtre.

Donc, chaque fois que possible, essayez pour que le code s'exécute dans le thread quitte proprement si nécessaire-le code lui-même doit détecter et gérer l'erreur. Il peut envoyer un message et / ou définir des statuts afin que le thread principal (ou un autre) sache ce qui s'est passé.

Préférence personnelle, dans les systèmes hautement disponibles, j'aime que mes threads tournent souvent (pas de verrouillage occupé) avec des délais d'attente spécifiques, appelant des fonctions non bloquantes et avec des conditions de sortie précises en place. Une variable' done ' globale ou spécifique à un thread fait l'affaire pour un nettoyage de sortie.

1
répondu robguima 2011-12-08 20:19:01