你目前正处于脱机状态,正在等待 Internet 重新连接

说明争用条件和死锁

重要说明:本文是由 Microsoft 机器翻译软件进行的翻译并可能由 Microsoft 社区通过社区翻译机构(CTF)技术进行后期编辑,或可能是由人工进行的翻译。Microsoft 同时向您提供机器翻译、人工翻译及社区后期编辑的文章,以便对我们知识库中的所有文章以多种语言提供访问。翻译的文章可能存在词汇、句法和/或语法方面的错误。Microsoft 对由于内容的误译或客户对内容的使用所导致的任何不准确、错误或损失不承担责任。

点击这里察看该文章的英文版: 317723
概要
Visual Basic.NET 或 Visual Basic 2005年提供了第一次在 Visual Basic 应用程序中使用线程的能力。线程引入调试问题 (例如,争用条件和死锁。本文探讨了这两个问题。
更多信息

争用条件

当两个线程同时访问共享的变量时,会发生争用条件。第一个线程读取该变量中,并从变量的第二个线程读取相同的值。然后第一个线程和第二个线程执行的值,其操作和他们竞争可查看哪个线程可以向共享变量上次写入值。保留的值将其值的线程上一次,因为线程写入值的前一个线程写入。

详细信息和示例

每个线程分配的时间,能够在一个处理器上执行的预定义期间。当线程分配的时间过期时,在处理器上,直到下一轮保存线程上下文和处理器开始的下一个线程的执行。

单行命令如何会导致争用条件?检查下面的示例以查看发生争用条件的方式。有两个线程,并且同时更新共享的变量称为(表示为dword ptr ds: [031B49DCh]程序集代码中)。

Visual Basic 代码:
   'Thread 1   Total = Total + val1				
   'Thread 2   Total = Total - val2				
从前面的 Visual Basic 代码的编译的程序集代码 (使用行号):
 'Thread 1 1.   mov         eax,dword ptr ds:[031B49DCh]  2.   add         eax,edi  3.   jno         00000033  4.   xor         ecx,ecx  5.   call        7611097F  6.   mov         dword ptr ds:[031B49DCh],eax 				
 'Thread 2 1.   mov         eax,dword ptr ds:[031B49DCh]  2.   sub         eax,edi  3.   jno         00000033  4.   xor         ecx,ecx  5.   call        76110BE7  6.   mov         dword ptr ds:[031B49DCh],eax 				
通过查看程序集代码,您可以看到多少个操作处理器在较低的级别来执行简单的加法计算的性能。一个线程可能能够在处理器上的时间执行全部或部分程序集代码。现在看此代码中发生争用条件的方式。

总计为 100、 val1 为 50,并且 val2 是 15。线程 1 获取机会执行,但只有完成步骤 1 到 3。也就是说线程 1 读取该变量,并且完成添加。线程 1 现在只等待写出其新值 150。在停止线程 1 后,线程 2 将得到完全执行。这意味着它已写入值它计算 (85) 出变量的总和。最后,线程 1 重新获得控制,并执行完毕。它写出的价值 (150)。因此,完成线程 1 后,汇总的值现在为 150 (而不是 85。

您可以看到如何,这可能是一个大问题。如果这是一个银行程序,客户必须钱他们不应该存在的帐户中。

此错误是随机的因为线程 1 上完成其执行其时间之前可能处理器已过期,然后线程 2 可以开始执行。这些事件发生时,如果未出现该问题。线程执行具有不确定性,因此您不能控制的时间或执行的顺序。此外应注意,线程可能会在运行时与调试模式下以不同的方式执行。此外,还会显示该系列中执行的每个线程时,如果未出现错误。此随机性使得这些错误跟踪和调试的难度大大增加。

要防止出现争用状态,可以锁定共享的变量,以便每次只有一个线程可以访问共享变量。这样做,请谨慎,因为如果变量在线程 1 中锁定和线程 2 还需要变量,线程 2 执行停止线程 2 等待线程 1,以释放该变量时。(有关详细信息,请参见本文的"参考"部分中的"SyncLock")。

症状

争用条件的最常见症状是不可预知的多个线程间共享的变量的值。这导致不可预测的线程中执行的顺序。一段时间有一个线程 wins,和一段时间另一个线程 wins。在其他情况下,执行正常工作。此外,如果单独执行每个线程,则变量值的正确行为。

死锁

当两个线程每一次锁定不同的变量,然后尝试锁定另一个线程已锁定的变量时,会发生死锁。因此,每个线程将停止执行,并等待另一个线程释放该变量。因为每个线程持有的变量,另一个线程需要,会有任何反应,并且线程保持被死锁。

详细信息和示例

下面的代码包含两个对象,LeftVal 和 RightVal:
'Thread 1SyncLock LeftVal SyncLock RightVal  'Perform operations on LeftVal and RightVal that require read and write. End SyncLockEnd SyncLock				
'Thread 2SyncLock RightVal SyncLock LeftVal  'Perform operations on RightVal and LeftVal that require read and write. End SyncLockEnd SyncLock				
允许线程 1 锁定 LeftVal 时发生死锁。处理器停止线程 1 的执行,并开始执行的线程 2。线程 2 锁 RightVal,然后选择尝试锁定 LeftVal。LeftVal 已被锁定,因为线程 2 将停止,并等待发布的 LeftVal。因为停止线程 2,则线程 1 允许继续执行。线程 1 尝试锁定 RightVal,但不能,因为线程 2 已被锁定。因此,线程 1 开始等待,直到 RightVal 变为可用。每个线程等待另一个线程,因为每个线程已锁定变量,等待另一个线程和线程都不解除锁定的变量所占用。

死锁并不常发生。如果处理器停止它之前,线程 1 执行这两个锁,线程 1 可以执行其操作,然后解除锁定的共享的变量。线程 1 解锁变量后,线程 2 可以继续执行,如预期的那样。

此错误似乎很明显,这些代码段的代码位于并排放置,而单独的模块或您的代码区域中出现的代码可能会在实践中。这非常硬错误跟踪,因为从这些相同的代码,可以发生正确执行和不正确的执行。

症状

死锁的一个常见症状是程序或一组线程将停止响应。这也就是被挂起。至少两个线程都每个等待另一个线程已锁定的变量。线程不继续,因为线程都不会释放其变量,直到它获得另一个变量。整个程序可能会挂起,如果程序正在等待一个或两个到完整的执行线程。

线程是什么?

用于分隔不同的应用程序在一台计算机上指定的时间执行的进程。操作系统不会执行的进程,但线程执行。线程是执行单位。操作系统线程的任务的执行分配给一个线程的处理器时间。一个进程可以包含多个执行线程。每个线程都维护其自己的异常处理程序,调度优先级和一组保存线程的上下文,如果该线程不能完成其执行期间的时间,它指派给处理器的操作系统使用的结构。下一次该线程接收处理器时间一直保持上下文。上下文包含线程无缝地继续其执行所需的所有信息。此信息包括线程的处理器的寄存器和主机进程的地址空间内的调用堆栈的一组。
参考
有关详细信息,Visual Studio 帮助中搜索以下关键字:
  • SyncLock.允许对象被锁定。如果另一个线程在试图锁定该同一对象,它是被阻止,直到第一个线程释放。SyncLock 谨慎使用,因为从 SyncLock 滥用,可能会出现问题。例如,此命令可以避免争用条件,但会导致死锁。
  • 联锁.允许选定的一组基本数字变量操作线程安全的。
有关其他信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:
316422 在 Visual Basic.NET 线程信息: 路线图
有关详细信息,请参阅下面的 MSDN 网站:

警告:本文已自动翻译

属性

文章 ID:317723 - 上次审阅时间:10/29/2013 02:35:00 - 修订版本: 3.0

Microsoft Visual Basic 2005, Microsoft Visual Basic .NET 2003 标准版, Microsoft Visual .NET 2002 标准版

  • kbvs2005swept kbvs2005applies kbinfo kbmt KB317723 KbMtzh
反馈