Почему ManualResetEvent не работает в этом синхронном вызове с использованием Silverlight 4? - PullRequest
5 голосов
/ 27 мая 2011

Давайте на время отложим вопрос о том, следует ли даже пытаться выполнять синхронные операции в контексте приложения Silverlight. Если я использую ManualResetEvent, как в следующем коде:

    static string result;
    static AutoResetEvent are = new AutoResetEvent(false);
    static ManualResetEvent mre = new ManualResetEvent(false);
    public static string AsyncCall()
    {
        string url = "https://stackoverflow.com/feeds/tag/silverlight";
        WebClient w = new WebClient();
        w.DownloadStringCompleted += new DownloadStringCompletedEventHandler(w_DownloadStringCompleted);
        w.DownloadStringAsync(new Uri(url), url);
        mre.WaitOne();
        return result;
    }

    static void w_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        result = e.Result;
        mre.Set();
    }

Как и следовало ожидать от чтения ManualResetEvent на MSDN , «Когда управляющий поток завершает действие, он вызывает метод Set, чтобы сигнализировать, что ожидающие потоки могут продолжить.», Когда Set () имеет значение вызывается в w_DownloadStringCompleted, элемент управления возвращается в ожидающий поток, который начал ожидание в AsyncCall. Это то, что происходит при запуске .NET 4.0. Поток в AsyncCall блокируется до завершения загрузки и вызова Set.

Если я выполню тот же фрагмент кода в Silverlight 4, будет вызван DownloadStringAsync, но элемент управления никогда не достигнет обратного вызова w_DownloadStringCompleted. Как только вызывается WaitOne (), этот поток в AsyncCall просто висит там, и поток, запущенный для обработки DownloadStringAsync, никогда не достигает обратного вызова. Единственный способ, которым я видел поток, достигающий обратного вызова загрузки в SL4, - это если поток из AsyncCall возвращается из AsyncCall. Поэтому Set () никогда не вызывается.

Почему ManualResetEvent не работает должным образом в Silverlight 4? Почему он отличается от .NET 4? Может быть, это применение Microsoft асинхронного шаблона проектирования? Или мне чего-то не хватает?

Спасибо

1 Ответ

3 голосов
/ 27 мая 2011

Сетевые обратные вызовы в Silverlight всегда будут поступать в том же потоке , в котором они были созданы. Например, если вы создадите WebClient.DownloadStringAsync в потоке пользовательского интерфейса (т.е. при событии нажатия кнопки), то вызов обратного вызова будет поставлен в очередь для доставки в тот же поток пользовательского интерфейса. Однако ваш вызов mre.WaitOne() блокирует поток пользовательского интерфейса, поэтому обратный вызов никогда не вызывается, а вызов mre.Set() никогда не происходит.

Так что да, это своего рода принуждение в асинхронности сетевых вызовов - вы действительно не можете делать синхронные вызовы, даже если они кажутся синхронными.

...