我想做什么: -在第一页加载之前从USB驱动器同步(甚至异步)加载设置
我做了什么: -在App.xaml.cs的OnLaunched方法中,我调用了此静态函数:
public static async void LoadSettings(string folderName = "Config", string fileName = "Settings.xml")
{
try
{
StorageFile configFile = null;
// scan through all devices
foreach (var device in await KnownFolders.RemovableDevices.GetFoldersAsync().AsTask().ConfigureAwait(false))
{
// folder that should have configuration
var configFolder = await device.GetFolderAsync(folderName).AsTask().ConfigureAwait(false);
if (configFile != null && configFolder != null && await configFolder.GetFileAsync(fileName).AsTask().ConfigureAwait(false) != null)
{
throw new Exception("More than one configuration file detected. First found configuration file will be used.");
}
else
configFile = await configFolder.GetFileAsync(fileName).AsTask().ConfigureAwait(false);
}
if (configFile == null)
throw new Exception("Configuration file was not found, please insert device with proper configuration path.");
string settingString = await FileIO.ReadTextAsync(configFile).AsTask().ConfigureAwait(false);
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
using (TextReader reader = new StringReader(settingString))
{
AppSettings = (Settings)serializer.Deserialize(reader); // store settings in some static variable
}
}
catch (Exception e)
{
//return await Task.FromResult<string>(e.Message);
}
//return await Task.FromResult<string>(null);
}
您现在可以看到,它是一个异步void方法,所以我什至不想与UI线程进行任何同步。它应该开火并做点什么。使用ConfigureAwait(false),我想确保它永远不会尝试返回上下文。最后的这些回报是我尝试过的其他事情的残余(我想做这种更好的方法,这是最原始的解决方案,但仍然行不通)。
无论如何,因为这就是乐趣的开始:当我使用Win 10在本地计算机上调试应用程序时,一切都很好,而且在Raspberry Pi 3上安装的Win 10 IOT上出现死锁线程(我今天从头开始安装了它,版本)。
但是僵局并不是最奇怪的事情。最奇怪的是什么时候出现。
就像我说的那样,该方法的调用看起来像这样:
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
Configuration.Settings.LoadSettings();
此方法中的所有操作正常之后,因此我导航到下面的第一页:
if (e.PrelaunchActivated == false)
{
if (rootFrame.Content == null)
{
rootFrame.Navigate(typeof(LogScreen), e.Arguments);
}
Window.Current.Activate();
}
一切仍然有效。用户需要编写他的代码,我检查该代码是否在设置中可用,然后该用户可以按“确定”进入下一页。在LogScreenViewModel的某个位置,此方法负责:
private void GoForward(bool isValid)
{
try
{
_navigationService.NavigateTo("MainPage"); // it's SimpleIoc navigation from MVVMLight
}
catch (Exception e)
{
Debug.WriteLine($"ERROR: {e.Message}");
}
}
当到达_navigationService.NavigateTo(“ MainPage”)时,就会发生死锁。基本上现在,UI线程冻结。如果等待了足够长的时间,我会在Output中看到捕获到的异常,说Messenger似乎已被占用(我无法显示屏幕,因为我现在无法访问该Raspberry),并且在超时后此线程被杀死(例如30秒)-在该用户界面线程解锁后,应用程序进入MainPage。在PC上不会发生这种情况-MainPage立即出现,没有异常,没有死锁。
我尝试在首页上等待大约1分钟,以检查是否会自行触发某些死锁异常,但事实并非如此。只有在尝试进入下一页后,它才会触发。
除了这种一劳永逸的方法之外,我还尝试了什么:
Window.Current.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () => await Configuration.Settings.LoadSettings(); ).AsTask().Wait();
如果我没有记错的话,它立即在Wait()上死锁,即使到处都存在ConfigureAwait(false),但这也发生在PC上。我想念什么?我还能尝试什么?因为老实说,在我看来,Win 10 IOT .NET运行时有错误或什么错误。
答案 0 :(得分:0)
我想我解决了这个问题。这段代码通常说来不是我的,经过一番挖掘之后,我发现我之前有人在导航到MainPage时尝试列出其他一些外部设备。它不是真正的异步安全代码(可能没有人意识到同步上下文),它只能在Win 10上工作,因为在台式机上它正在寻找COM0设备,而我只有COM2,因此引起麻烦的方法甚至没有在全部。
我仍然不知道它与我的配置有多相关(因为某种原因它在没有它的情况下仍然可以工作),但是在我修复了这个旧的非异步安全代码的问题之后,它开始表现出预期的效果。