问题现象:一旦出现了这样的错误,系统就汇报错"itemsdescription.xml文件正在由另一个进程使用"(itemsdescription.xml就是那个临时文件)。
问题的解决方案:
1、将临时文件的写入和保存工作放到一个方法中,并把这个方法放到系统线程池的方法队列中等待执行。
将耗时的任务从UI线程中剔除,放到工作线程或是线程池线程中
ThreadPool.QueueUserWorkItem(new WaitCallback(AsynSaveTempXml),treenode);
2、在异步执行的方法中对临时文件进行操作,通过声明一个全局的XmlDocument 对象xmlDoc以实现对对象的线程同步。
注意对对象的线程同步
private void AsynSaveTempXml(TreeNode treenode)
{
lock (xmlDoc)
{
//... ...xmlDoc的写入
//... ...xmlDoc.Save(filepath);
}
myTree.BeginInvoke(new PopulateWebBrowserHandler(this.PopulateWebBrowser));
}
3、从UI线程中异步调用UI的刷新方法(即,填充web控件),不要在工作线程或线程池线程的方法中对UI进行处理,一定要通过BeginInvoke方法回到UI线程进行操作。
回过头来看,问题的解决很简单(对于高手来说)。但还是有一些原则性的问题需要留意的:
1、对于比较耗时(或是在某些情况下可能会比较耗时)的任务一定要异步来执行,否则就可能会出现问题,比如像我遇到的问题这样或者UI线程的阻塞etc。不要吝啬于线程切换所产生的开销,这一点开销远比单线程所带来的问题要强上许多。
2、.net下的用于线程同步的机制应该不止lock这一种,但是作为比较轻量级的用于对象的同步,monitor就已经足够了(lock实际上就是monitor的两个方法的封装---enter和exit),当然了,如果是进程同步就另当别论了。
3、如果没有特殊原因也没有必要自定义线程,完全可以用线程池来实现时异步机制。当然了,如果你需要对线程的优先级进行设置,或者需要获取某些线程的属性例如:name等等还是应该是用自定义线程的。
4、不要在工作线程中对UI进行修改,一定要通过Control.BeginInvoke()方法来调用修改UI的方法。