涛's profileBruno YuBlogLists Tools Help

Bruno Yu

涛 于

Occupation
Location
Interests
Microsoft GCR CSS IBS MSDN Forums
There are no categories in use.
by 
by 
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将线程BDSCS 都推入栈中。此时目标账户无增加,因为还没有执行增加,总额发生变化。而此时如果有另外的线程执行统计,打印结果一定会出错。但如果将最后一次打印延迟(时间不能确定,因为该线程何时出栈不能确定),等待被中断的线程被弹出栈继续执行,最后打印的银行总额一定是正确的。

然而,打印顺序并不是升序排列,而是混乱排列,增加统计并打印之间一样可能存在中断,此时需要研究中断的类型:

1. I/O中断——当外部设备或通道操作正常结束或发生某种错误时发生的中断。I/O传输出错,传输结束等。

2. 外中断——CPU外部非通道式装置引起的中断。如时钟中断,操作员控制台中断等。

3. 机器故障中断——硬件中断,如电源故障,通道与主存交换信息时主存出错,从主存取指令出错,取数据出错等

4. 访管中断——OS提出某种需求时发出的中断。

在分时机制中,你能确定中断的产生是因为时间片到(产生外中断)还是I/O中断?在执行序列中,同一位置产生的中断,完全有可能是不同原因产生的,即中断类型不一致。虽然CPU需要读取中断向量来确定当前的中断类型,但这一操作对我们来说是不可见的(笔者没有接触过Advanced Programmable Interrupt Controller,不知道能不能实现用户读取中断类型)。第二,同类型中断,在执行序列中产生的位置也不能确定,时间分片机制就是一例。因为在执行语句时,无法确定时间片用完时执行序列到了哪个部分,也就无法确定它在哪个部分被中断。

基于以上两点,没有同步和锁的多线程程序会产生不可预见的错误,你不知道中断的位置,不能确定哪些操作还没有进行,后果便不可预期了。另外,已经被中断的线程何时才从栈中弹出继续执行?在高压(CPU利用率高,内存满载)情况下,已经被中断的线程要被弹出基本上已经不可能了,因为高压情况下中断过于频繁,不断有信的线程或进程压入栈中。最终可能导致CPU无法处理这些数据,系统失去响应,被中断的线程无法弹出继续执行。

拓展一下:如果错误是由中断和其他因素符合生成,比如多线程程序中出现的遗失更新问题,它是由非原子性操作和中断造成的。如++variable,其紧凑的语法格式更像一个单独的操作。而它执行的序列是读-改-写,结合之前的中断考虑,为什么会遗失更新,显而易见。(因为执行序列过程中的中断会导致不可预期的结果——整理者注)

最后请思考:为什么进程中断不会导致不可遇见的错误,而线程中断却会引发这些错误呢?

线程与进程相似,是一段完成某个特定功能的代码,是程序中单个顺序的流控制;但与进程不同,同类多线程共享一块内存空间和一组系统资源,而线程本身的数据通常只有微处理器的寄存器数据以及一个供程序执行时使用的的堆栈,而中断恰恰处理的就是将寄存器的数据压入栈中的。

结语:多核时代已经来临,随之而来的并行开发将大行其道,多线程是基础也是关键。在并行开发中,有一个重要的概念就是线程安全。我们要学习完善自己的思维,像多线程一样思考,会让你在并行开发中走的顺利一些。

April 16

FileExtInfo

今天发现一个好工具,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

关于ClickOnce中Stdole.dll文件的部署问题

原帖: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 04

两个常见问题的讨论

1. 原帖:serial port DataReceived event not triggering

只要涉及到.NETSerialPort类的编程,一般都会牵扯到这个问题。这篇Thread是我目前搜集到的关于这个问题最完整的论述。其实也包括 BCL Blog中的一些信息。很多时候还是感觉BCL Blog的信息不太够用,MSDN的文档又没有充分的说明,好在论坛中产品组和MVP们为这些技术的改进做了很大的贡献。

2.
原帖:Change TimeZone at runtime

经常被提及的一个问题,具体问题具体分析。看以后对这个问题能不能有更深入的探讨。

April 02

GetOpenFileName API的BUG

原帖:openFileDialog 'This file is in use'

客户在用OpenFileDialog控件打开多个文档时出错,因为这个控件在打开多个文档的时候会对文件进行访问,从而导致某些不可访问的文件使打开多个文档失败。而打开单个文件的时候不会出现这个问题。

原因很简单,是由于这个组件调用的GetOpenFileName APIBUG导致的。客户有些抱怨: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.