Est-Tâche.Usine.StartNew() de la garantie d'utiliser un autre thread que le thread appelant?

Je suis en train de créer une nouvelle tâche à partir d'une fonction, mais je ne voudrais pas qu'il fonctionne sur le même thread. Je n'aime pas le thread qui tourne sur de tant qu'il est un autre (de sorte que l'information donnée dans cette question n'aide pas).

Suis-je garanti que le code ci-dessous sera toujours la sortie TestLock avant de permettre à Task t de le saisir à nouveau? Si non, qu'est-ce que les recommandations de conception de motif pour empêcher la ré-entrency?

object TestLock = new object();

public void Test(bool stop = false) {
    Task t;
    lock (this.TestLock) {
        if (stop) return;
        t = Task.Factory.StartNew(() => { this.Test(stop: true); });
    }
    t.Wait();
}

Edit: Basé sur la ci-dessous la réponse de Jon Skeet et Stephen Toub, un moyen simple de façon déterministe empêcher la réentrée serait de passer un CancellationToken, comme l'illustre cette méthode d'extension:

public static Task StartNewOnDifferentThread(this TaskFactory taskFactory, Action action) 
 {
    return taskFactory.StartNew(action: action, cancellationToken: new CancellationToken());
}
  • Je doute que vous ne peut garantir qu'un nouveau fil de discussion sera créé lors de l'appel de StartNew. Une tâche est définie comme une opération asynchrone, ce qui n'implique pas nécessairement un nouveau thread. Peut utiliser un fil de discussion existant aussi quelque part, ou une autre façon de faire asynchrone.
  • Si vous êtes à l'aide de C# 5, envisager de remplacer t.Wait() avec await t. Wait ne correspond vraiment pas à la philosophie de TPL.
  • Dans le code le plus efficace comportement serait si c' a utilisez le thread appelant. Ce thread est assis là à ne rien faire, après tout.
  • Oui, c'est vrai, et je n'aurais pas l'esprit dans ce cas précis. Mais je préfère un comportement déterministe.
  • Si vous utilisez un planificateur qui exécute uniquement les tâches sur un thread spécifique alors non, la tâche ne peut pas être exécuté sur un thread différent. Il est très courant d'utiliser un SynchronizationContext à assurez-vous que les tâches sont exécutées sur le thread de l'INTERFACE utilisateur. Si vous avez exécuté le code qui a appelé StartNew sur le thread d'INTERFACE utilisateur comme ça, alors qu'ils seraient tous les deux sur le même thread. La seule garantie est que la tâche sera exécutée de manière asynchrone de la StartNew appel (au moins si vous ne fournissez pas un RunSynchronously drapeau.
  • Si vous souhaitez de "forcer" un nouveau thread pour être créé, utilisez la fonction " TaskCreationOptions.LongRunning' drapeau. par exemple: Task.Factory.StartNew(() => { this.Test(stop: true); }, TaskCreationOptions.LongRunning); Qui est une bonne idée si vos serrures pourrait mettre le fil dans un état d'attente pour une longue période de temps.
  • Erwin, si vous voulez vraiment fonctionner sur des threads séparés n'est-ce pas mieux fait de créer et d'utiliser des threads de façon explicite?
  • La seule condition est de s'exécuter sur un autre thread, il serait exagéré que le pool de threads (en particulier via la bibliothèque de Tâches) est bien capable de gérer cela correctement.
  • Pourquoi est - 'si(arrêt) return' vérifier à l'intérieur de la serrure ici? Que bool est local, pas besoin de protéger, sur lire (sûrement)
  • L'idée était d'empêcher la sortie de la fonction (qui est juste un exemple d'action) jusqu'à ce que le verrou peut être acquise. Dans une situation réelle, vous seriez en droit de déplacer cette déclaration avant de la verrouiller.
  • la solution a fonctionné pour moi 🙂
  • LongRunningTask ne garantit PAS un nouveau fil, fournit un indicateur de TPL. Un nouveau fil de discussion peuvent être utilisés, mais ne sont pas garanties. Comme ilustrated par la réponse correcte, seulement CancellationToken n'est que

InformationsquelleAutor Erwin Mayer | 2012-09-03