April 17
在应用多线程时,如果不通过同步或者锁,程序会出现许对无法预期的错误,如更新丢失等等。举例:定义一个Bank类包含一个transfer()方法,将一定数额的钱从一个指定账户里转移到目标账户。假设时内部转移且银行与外界没有资金流动,即总金额固定。然后在run()中调用这个方法,没有任何锁和同步。
运行这个模拟程序后,最初的交易中总额无变化;但当运行一段时间后,总额就开始发生变化,这就是多线程程序最容易遇见的错误,存取不同步造成的。损失的金额流向何方?讨论之前,先看一个重要概念——中断。
时间分片机制和中断是多进程和多线程的基础,换个角度,时间分片机制其实也是利用中断实现的。因为它是在进程消耗完该时间片后,由Programmable
Interval Timer (PIT)产生一个外部中断,从而实现进程间的切换。另外,分时机制下,资源是先分配给进程,再由进程分配给线程。
CPU执行程序时,程序存放在CS(Code Segment),相关数据存放在DS(Data Segment)中。当CPU响应中断后,会依次做以下事情:
1. 通过一系列推入堆栈指令来保护中断现场,即保护CPU各寄存器的值;
2. 中断处理;
3. 中断处理模块之后,通过一系列弹出堆栈指令,用于恢复各寄存器的值;
4. 中断返回指令。
而产生中断的程序会根据中断类型号,到内存0段中找到中断向量,再根据中断向量转入相应的中断处理程序。回到之前的例子,假设线程A开始运行,无中断执行情况如下:扣除指定账户金额->增加目标账户金额->同济总金额并打印
金额为何会减少?则看产生中断执行的情况(线程B):扣除->线程被中断->中断返回指令->增加->统计
当中断产生,CPU将线程B的DS和CS 都推入栈中。此时目标账户无增加,因为还没有执行“增加”,总额发生变化。而此时如果有另外的线程执行“统计”,打印结果一定会出错。但如果将最后一次打印延迟(时间不能确定,因为该线程何时出栈不能确定),等待被中断的线程被弹出栈继续执行,最后打印的银行总额一定是正确的。
然而,打印顺序并不是升序排列,而是混乱排列,“增加”和“统计并打印”之间一样可能存在中断,此时需要研究中断的类型:
1. I/O中断——当外部设备或通道操作正常结束或发生某种错误时发生的中断。I/O传输出错,传输结束等。
2. 外中断——CPU外部非通道式装置引起的中断。如时钟中断,操作员控制台中断等。
3. 机器故障中断——硬件中断,如电源故障,通道与主存交换信息时主存出错,从主存取指令出错,取数据出错等
4. 访管中断——对OS提出某种需求时发出的中断。
在分时机制中,你能确定中断的产生是因为时间片到(产生外中断)还是I/O中断?在执行序列中,同一位置产生的中断,完全有可能是不同原因产生的,即中断类型不一致。虽然CPU需要读取中断向量来确定当前的中断类型,但这一操作对我们来说是不可见的(笔者没有接触过Advanced
Programmable Interrupt Controller,不知道能不能实现用户读取中断类型)。第二,同类型中断,在执行序列中产生的位置也不能确定,时间分片机制就是一例。因为在执行语句时,无法确定时间片用完时执行序列到了哪个部分,也就无法确定它在哪个部分被中断。
基于以上两点,没有同步和锁的多线程程序会产生不可预见的错误,你不知道中断的位置,不能确定哪些操作还没有进行,后果便不可预期了。另外,已经被中断的线程何时才从栈中弹出继续执行?在高压(CPU利用率高,内存满载)情况下,已经被中断的线程要被弹出基本上已经不可能了,因为高压情况下中断过于频繁,不断有信的线程或进程压入栈中。最终可能导致CPU无法处理这些数据,系统失去响应,被中断的线程无法弹出继续执行。
拓展一下:如果错误是由中断和其他因素符合生成,比如多线程程序中出现的遗失更新问题,它是由非原子性操作和中断造成的。如++variable,其紧凑的语法格式更像一个单独的操作。而它执行的序列是读-改-写,结合之前的中断考虑,为什么会遗失更新,显而易见。(因为执行序列过程中的中断会导致不可预期的结果——整理者注)
最后请思考:为什么进程中断不会导致不可遇见的错误,而线程中断却会引发这些错误呢?
线程与进程相似,是一段完成某个特定功能的代码,是程序中单个顺序的流控制;但与进程不同,同类多线程共享一块内存空间和一组系统资源,而线程本身的数据通常只有微处理器的寄存器数据以及一个供程序执行时使用的的堆栈,而中断恰恰处理的就是将寄存器的数据压入栈中的。
结语:多核时代已经来临,随之而来的并行开发将大行其道,多线程是基础也是关键。在并行开发中,有一个重要的概念就是线程安全。我们要学习完善自己的思维,像多线程一样思考,会让你在并行开发中走的顺利一些。
April 16
今天发现一个好工具,FileExtInfo。此工具可以快速全面的提供与文件类型关联的注册表键,以确定在编程访问某些文件时最终发现是注册表问题的 场合。在这个工具的UI中,选中文件的扩展类型,当双击扩展名或点击View file
assiciation report时,会生成相应的txt文档,内容包含所有与这个文件关联的注册表中的键值对的信息,非常方便实用。
下载地址:http://windowsxp.mvps.org/fileextinfo.htm
原帖:System.Diagnostics.Process.Start not opening the PDF document
以PDF为例在我的测试机中生成的txt文档内容:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
File association information for [.PDF] file type
Generated by FileExtInfo v2.0 on 2008-4-16 13:18:26
FileExtInfo ? 2005-2007 Ramesh Srinivasan.
Homepage: http://www.winhelponline.com
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
indows
Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\.PDF]
"Content Type"="application/pdf"
@="AcroExch.Document"
[HKEY_CLASSES_ROOT\.PDF\OpenWithList]
@=""
[HKEY_CLASSES_ROOT\.PDF\OpenWithList\AcroRd32.exe]
@=""
[HKEY_CLASSES_ROOT\.PDF\PersistentHandler]
@="{F6594A6D-D57F-4EFD-B2C3-DCD9779E382E}"
[HKEY_CLASSES_ROOT\.PDF\ShellEx]
[HKEY_CLASSES_ROOT\.PDF\ShellEx\{8895b1c6-b41f-4c1c-a562-0d564250836f}]
@="{49400A7C-81A8-4F52-8CCE-D54739EE87EC}"
indows
Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\AcroExch.Document]
"BrowseInPlace"="1"
"EditFlags"=hex:00,00,01,00
@="Adobe Acrobat Document"
[HKEY_CLASSES_ROOT\AcroExch.Document\CLSID]
@="{B801CA65-A1FC-11D0-85AD-444553540000}"
[HKEY_CLASSES_ROOT\AcroExch.Document\CurVer]
@="AcroExch.Document.7"
[HKEY_CLASSES_ROOT\AcroExch.Document\Shell]
[HKEY_CLASSES_ROOT\AcroExch.Document\Shell\Open]
[HKEY_CLASSES_ROOT\AcroExch.Document\Shell\Open\Command]
@="\"C:\\Program Files\\Adobe\\Reader
8.0\\Reader\\AcroRd32.exe\" \"%1\""
indows
Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.PDF]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.PDF\OpenWithList]
"a"="AcroRd32.exe"
"MRUList"="adcb"
"b"="TM.exe"
"c"="msnmsgr.exe"
"d"="Maxthon.exe"
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.PDF\OpenWithProgids]
"AcroExch.Document"=hex(0):
April 08
原帖:Error mesg on target system w/OneClick install...
问题:Unable to install
or run the application. The application requires that assembly stdole
Version 7.0.3300.0 be installed in the global assembly cache (GAC) first.
Please contact your system administrator.
讨论一:Problems
with stdole.dll: This is a known bug in Beta2 & is being addressed. To
workaround this problem, open your project references & delete the refernce
to stdole.dll.
截至到发帖时间,此帖被浏览了20389次,可见这个问题的普遍程度。
讨论二:error
when client using clickonce install: Try going to your project properties
and under the references tab you'll see an option for unused references, click
that and it will remove any unused references which may be the stdole.
被浏览了2863次。
讨论三:ClickOnce
Deployment Error: I'm glad you both figured out how to solve the
installation problem. However, I wanted to take the opportunity to explain what
is going on. Visual Studio 2005 tries to be smart about how to deploy
references. If the reference has CopyLocal=true, then the reference will
be published with the application, by default. If the reference has
CopyLocal=false (which is the default when the a reference is installed in the
gac, then the reference will be marked as a prerequisite. This means the
assembly must be installed in the client's GAC before the ClickOnce application
will install. There are some assemblies that are install into the GAC because
of the Visual Studio install, not the .NET FX install. It sounds like
this is the situation you both got into.
此帖被浏览了11680次。
April 02
原帖:openFileDialog 'This file is in use'
客户在用OpenFileDialog控件打开多个文档时出错,因为这个控件在打开多个文档的时候会对文件进行访问,从而导致某些不可访问的文件使打开多个文档失败。而打开单个文件的时候不会出现这个问题。
原因很简单,是由于这个组件调用的GetOpenFileName
API的BUG导致的。客户有些抱怨:So much for managed
code - back to the API并询问是否可以修正。我认为Tech
Leader对这个问题的回复非常巧妙:
Thanks for posting this issue. I guess it is less likely that the developers
will fix this on Windows XP. Internally, the file open browser goes quite
different code paths for single-selection and multi-selection. For the
multi-selection scenario, additional check is made. Hence we are seeing the
different behavior.
On Windows Vista, we have a new version of the browser dialog, which is invoked
by "System.Windows.Forms.FileDialog.RunDialogVista" in .Net. It does
not have the problem. Even if we use the old file open browser dialog (by
setting "AutoUpgradeEnabled") on Vista, it still seems to work fine.
So I believe the issue should be fixed on Vista.