Подтвердить что ты не робот

Задача продолжения в той же теме, что и предыдущая

У меня есть WebService, который создает задачу и задачу продолжения.

В первой задаче мы устанавливаем Thread.CurrentPrincipal

Следовательно, когда запускается ContinuationTask, у него больше нет Thread.CurrentPrincipal.

Я хотел бы указать в ContinuationTask, что он должен работать в том же потоке, что и его предшественник.

Я искал в Интернете, но я нашел требование для потока для запуска в SynchronizationContext, поэтому я начинаю думать, что мне не хватает какого-то основного правила, особенно в отношении того, как Thread.Principal должен работать.

4b9b3361

Ответ 1

Прежде всего, не используйте TaskContinuationOptions.ExecuteSynchronously для этой цели! Вы не можете принудительно продолжить продолжение в одном потоке. Он работает только с очень высокой вероятностью. Всегда есть случаи, когда это не работает: слишком большая рекурсия приведет к тому, что TPL не будет выполняться синхронно. Пользовательские TaskScheduler также не обязаны поддерживать это.

Это распространенное заблуждение, особенно потому, что оно неправильно распространено в Интернете. Вот некоторые чтения по этой теме: http://blogs.msdn.com/b/pfxteam/archive/2012/02/07/10265067.aspx

Если вам нужно запустить один поток, сделайте следующее:

Task.Factory.StartNew(() => { First(); Second(); });

Так просто.

Позвольте мне проиллюстрировать, почему это работает, показывая альтернативное решение:

void MyCompositeTask()
{
  var result = First();
  Second(result);
}
Task.Factory.StartNew(() => MyCompositeTask());

Это выглядит более интуитивно: мы передаем MyCompositeTask в TPL для запуска. TPL не заботится о том, что мы делаем в нашем обратном вызове. Мы можем делать все, что захотим, включая вызов нескольких методов и передачу результатов.

Ответ 2

Из моего учебника по С# (С# 4.0 в двух словах):

Вы можете заставить их [задачи продолжения] выполнить в том же потоке [как их антецедент], указав TaskContinuationOptions.ExecuteSynchronously при вызове ContinueWith: это может улучшить производительность в очень мелкозернистых продолжениях с уменьшением косвенности.

В принципе, я не пробовал это, но, похоже, это то, что вы ищете, и может использоваться в сочетании с Thread.CurrentPrincipal.

Вот ссылка на статью MSDN и еще несколько конкретных примеров.

Ответ 3

Настройка идентификатора потока пула не является хорошей идеей. Он связывает вас с этим конкретным потоком и рискует "утечить" личность в случае исключений, если вы забудете очистить личность в обработчике исключений. Вы можете столкнуться с несвязанными задачами, запущенными с использованием "утечки".

Попробуйте передать объект WindowsIdentity в задачи и выдать себя за использование WindowsIdentity.Impersonate. Это позволит вам использовать любой доступный поток и безопасно очистить личность, даже если возникает исключение.

Вы можете попробовать что-то вроде этого:

WindowsPrincipal myPrincipal=...;
...
var identity=(WindowsIdentity)myPrincipal.Identity;
var task=Task.Factory.StartNew(ident=>{
        var id=(WindowsIdentity)ident;
        using(var context=id.Impersonate())
        {
            //Work using the impersonated identity here
        }
        return id;
    },identity).
.ContinueWith(r=>{
        var id = r.Result;
        using(var context=id.Impersonate())
        {
            //Work using the impersonated identity here
        }
});

Операторы using гарантируют, что выданный личность очищается, даже если возникает исключение.

Ответ 4

Вызвать продолжение с помощью TaskScheduler.FromCurrentSynchronizationContext():

Task UITask= task.ContinueWith(() =>
{
 this.TextBlock1.Text = "Complete"; 
}, TaskScheduler.FromCurrentSynchronizationContext());

Скопировано из fooobar.com/info/36359/...