2015-07-19 5 views
2

У меня возникли проблемы, связанные с культурой между потоками. Мне удалось немного работать, используя контекст синхронизации, но в одной части моего кода я использую Task.Yield(). После этого фрагмента кода мой контекст потерян, что означает, что все последующие ожидания/выходы после этой точки не используют мой собственный SynchronizationContext.SynchronizationContext потерял после Task.Yield()

Я сварил его до очень простого теста, и я вижу, что после нашей задачи. Наш ресурс SynchronizationContext потерян.

синхронизации Контекст Класс:

public class TestSynchronizationContext : SynchronizationContext 
{ 
} 

Unit Test:

[Test] 
public async Task TestHere() 
{ 
    TestSynchronizationContext context = new TestSynchronizationContext(); 
    SynchronizationContext.SetSynchronizationContext(context); 
    var something1 = SynchronizationContext.Current; 
    await Task.Yield(); 
    var something = SynchronizationContext.Current; 
} 

EDIT: Если я использую новую задачу, контекст сохраняется, если я могу передать в правильном TaskScheduler (Хотя .. Это планировщик, а не контекст синхронизации). Такие, как:

[Test] 
public async Task TestHere() 
{ 
    TestSynchronizationContext context = new TestSynchronizationContext(); 
    SynchronizationContext.SetSynchronizationContext(context); 
    CultureInfo taskCulture = null; 
     Task.Factory.StartNew(
      () => { taskContext = SynchronizationContext.Current; }, 
      CancellationToken.None, 
      TaskCreationOptions.None, 
      TaskScheduler.FromCurrentSynchronizationContext() 
      ).Wait(); 
    Assert.AreEqual(context.GetType(), taskContext.GetType()); 
} 
+0

В вашем случае 'TestSynchronizationContext.Post' действительно вызывается логикой' YieldAwaitable', но [все это делается по умолчанию] (http://referencesource.microsoft.com/#mscorlib/system/threading/synchronizationcontext.cs , 16705ba05372139e, ссылки) вызывает 'ThreadPool.QueueUserWorkItem' для обратного вызова продолжения. Поэтому после «ожидания» вы попадаете в случайный поток ThreadPool без какого-либо контекста синхронизации и без вашего объекта «Culture». – Noseratio

+1

Измените тестовый пример: вместо 'Task.Factory.StartNew (...) .Wait();', поместите 'var task = Task.Factory.StartNew (...); Thread.Sleep (1000); task.Wait(); '. – PetSerAl

ответ

3

Ваш SychronizationContext должен установить себя в качестве Current. Если ваш SynchronizationContext предназначен для выделенного потока, вы можете просто установить текущий один раз в своем основном цикле; если он использует потоки пула потоков для выполнения (как в вашем примере кода), вы должны устанавливать его каждый раз, когда вы занимаете один из потоков (и очищаете его, прежде чем возвращать поток в пул потоков, конечно).

+0

Но, например, если я запустил новую Задачу, внутри этой Задачи, у нее будет правильный Контекст. Это происходит только после Task.Yield. – MindingData

+0

@MindingData: Я не уверен, что вы подразумеваете под «началом новой« Задачи ». Если вы имеете в виду «вызов метода async Task», то да, «Текущий» все тот же, поскольку вы находитесь в одном потоке. OTOH, если вы * на самом деле * "запустите новую' Задачу' "(т. Е. Используйте' Task.Run'), то 'Current' не будет передано новой задаче. –

+0

Добавлено редактирование для вас. При запуске задачи он может принять параметр TaskScheduler, который я могу передать в контексте синхронизации, поэтому я могу заставить его работать в этом смысле, но не может использовать его таким образом, используя Task.Yield() – MindingData

Смежные вопросы