[c#] Définir le délai d'attente pour une opération



Answers

Plus simplement en utilisant Task.Wait(TimeSpan) :

using System.Threading.Tasks;

var task = Task.Run(() => obj.PerformInitTransaction());
if (task.Wait(TimeSpan.FromSeconds(30)))
    return task.Result;
else
    throw new Exception("Timed out");
Question

J'ai l'objet obj qui est le composant de 3ème partie,

// this could take more than 30 seconds
int result = obj.PerformInitTransaction(); 

Je ne sais pas ce qui se passe à l'intérieur. Ce que je sais, c'est que si ça prend plus de temps, c'est raté.

comment configurer un mécanisme de temporisation pour cette opération, de sorte que si cela prend plus de 30 secondes, je lance simplement MoreThan30SecondsException ?




Il y a un bel exemple d'une solution générique à cela en utilisant une classe d'aide here .

Il utilise le délégué Action pour éviter la création / destruction de Thread présentée dans l'exemple précédent.

J'espère que ça aide.




Voici deux implémentations qui lancent également toute exception qui se produit dans la tâche interne.

Pour les actions (pas de valeur de retour):

public static bool DoWithTimeout(Action action, int timeout)
{
    Exception ex = null;
    CancellationTokenSource cts = new CancellationTokenSource();
    Task task = Task.Run(() =>
    {
        try
        {
            using (cts.Token.Register(Thread.CurrentThread.Abort))
            {
                action();
            }
        }
        catch (Exception e)
        {
            if (!(e is ThreadAbortException))
                ex = e;
        }
    }, cts.Token);
    bool done = task.Wait(timeout);
    if (ex != null)
        throw ex;
    if (!done)
        cts.Cancel();
    return done;
}

Pour Funcs (avec valeur de retour):

public static bool DoWithTimeout<T>(Func<T> func, int timeout, out T result)
{
    Exception ex = null;
    result = default(T);
    T res = default(T);
    CancellationTokenSource cts = new CancellationTokenSource();
    Task task = Task.Run(() =>
    {
        try
        {
            using (cts.Token.Register(Thread.CurrentThread.Abort))
            {
                res = func();
            }
        }
        catch (Exception e)
        {
            if (!(e is ThreadAbortException))
                ex = e;
        }
    }, cts.Token);
    bool done = task.Wait(timeout);
    if (ex != null)
        throw ex;
    if (done)
        result = res;
    else
        cts.Cancel();
    return done;
}



Vous devez faire attention à interrompre une opération comme celle-ci, d'autant plus que c'est dans un composant tiers que vous n'avez (éventuellement) pas accès au code à modifier.

Si vous annulez l'opération, vous ne saurez pas dans quel état vous avez laissé la classe sous-jacente. Par exemple, elle a peut-être acquis un verrou et votre sujet a provoqué la désactivation de ce verrou. Même si vous détruisez l'objet après l'annulation de l'opération, il peut avoir modifié un état qui lui est global et vous ne pourrez donc pas créer une nouvelle instance sans redémarrage de manière fiable.






Links