2009-11-06 5 views
5

Je souhaite implémenter des tâches interruptibles basées sur des threads d'arrière-plan. Quel est le moyen le plus propre d'implémenter la méthode TTask.Stop? Comment puis-je abandonner le thread d'arrière-plan?Annuler un fil?

Le code exécuté dans le contexte de thread est passé à la tâche en utilisant une méthode anonyme et peut contenir des appels bloquants, donc je ne peux pas compter sur le fait que le drapeau Terminated est vérifié régulièrement depuis le code.

Merci pour toute contribution.

Utiliser D2010 dans le cas où il importe (certaines choses dans TThread semblent avoir changé)

Répondre

7

Il n'y a aucun moyen d'interrompre en toute sécurité un fil conducteur. Cela est vrai pour les programmes Windows, qu'ils soient écrits en Delphi ou non, et que vous utilisiez Delphi 2010 ou une version antérieure. C'est une limitation du système d'exploitation si vous voulez l'appeler ainsi, mais en fait c'est une limitation du threading, avorter un thread sans vous assurer qu'il ne contient pas de verrou ou quelque chose comme ça va faire des ravages avec votre programme.

Ce que vous pouvez faire est d'appeler la fonction API TerminateThread(), qui est mal. Lisez la liste des problèmes et des avertissements dans ce lien et voyez si vous voulez toujours l'appeler. Il n'y a pas d'autre moyen qui fonctionne sans la coopération du code de tâche.

7

Isolez le travail dans un processus distinct. Selon la façon dont vous communiquez avec le travail d'arrière-plan, c'est probablement le meilleur moyen de garantir que vous pouvez l'abandonner proprement. Par exemple, il n'est probablement pas bon d'utiliser la mémoire partagée pour la communication; utiliser des fichiers ou des tuyaux, ou un mécanisme similaire qui ne se casse pas ou ne bloque pas lorsque l'autre extrémité est tuée. Si vous utilisez des mutex nommés pour la synchronisation entre processus, sachez qu'il existe un état d'erreur particulier pour ces primitives de synchronisation: WAIT_ABANDONED est renvoyé par WaitForSingleObject et ses amis si un thread (ou, implicitement, le thread principal du processus) qui a tenu la primitive terminé sans le libérer proprement. Fondamentalement, cela signifie que vous devez utiliser une approche transactionnelle par étapes pour le transfert de données, de sorte que vous puissiez ignorer un état éventuellement incohérent qui était en cours de modification au moment de la résiliation.

+0

C'est une bonne réponse (+1); cf. Python threading, où beaucoup est fait du Global Interpreter Lock qui est responsable à la fois de la sécurité du thread (bien) et à toutes fins pratiques limite le code multithread à un seul noyau (mauvais). La meilleure solution à ce problème consiste à ne pas utiliser de threads, mais plutôt des processus via le package multitraitement, et ce qui est gagné par cette capacité instantanée de mise à l'échelle sur plusieurs machines, ce qui devient nécessaire pour une mise à l'échelle importante. Au lieu de se soucier de la sécurité des threads, il serait préférable d'avoir une gestion multi-processus facile (plus facile) dans Delphi. –

+0

Les sémaphores n'ont pas un état "abandonné" car ils n'ont aucune notion intégrée de propriété. (En ce qui concerne l'OS, un thread ne peut pas "tenir" un sémaphore.) Seul un mutex peut être abandonné de manière détectable. –

+0

Cela peut être une bonne façon de mettre en œuvre des tâches interruptibles avec le code de blocage, mais je ne vois pas comment la fonctionnalité dans la question (une tâche interruptible pour les méthodes anonymes) devrait être mis en œuvre comme celui-ci avec Delphi. Il devrait y avoir un compilateur d'exécution, pour créer un exécutable (être engendré comme un processus différent) de la méthode anonyme, pas là? – mghie