首页 / 知识
关于多线程:什么是竞争条件?
2023-04-13 15:03:00
What is a race condition?编写多线程应用程序时,遇到的最常见问题之一是竞争条件。 我对社区的问题是: 什么是比赛条件? 你怎么发现它们? 你怎么处理它们? 最后,你如何防止它们发生? 当两个或多个线程可以访问共享数据并且他们尝试同时更改它时,会发生竞争条件。因为线程调度算法可以在任何时间在线程之间交换,所以您不知道线程将尝试访问共享数据的顺序。因此,数据变化的结果取决于线程调度算法,即两个线程都"竞相"访问/改变数据。 当一个线程执行"check-then-act"时(例如,"检查",如果值为X,然后"执行"以执行取决于值为X的操作)并且另一个线程对该值执行某些操作时,通常会出现问题在"检查"和"行为"之间。例如:
关键是,y可以是10,或者它可以是任何东西,这取决于另一个线程是否在检查和行为之间改变了x。你没有真正的认识方式。 为了防止发生竞争条件,您通常会锁定共享数据,以确保一次只能有一个线程访问数据。这意味着这样的事情:
当访问共享资源的多线程(或其他并行)代码可能以导致意外结果的方式执行时,存在"竞争条件"。 举个例子:
如果您有5个线程同时执行此代码,则x WOULD NOT的值最终为50,000,000。事实上,每次运行都会有所不同。 这是因为,为了使每个线程增加x的值,它们必须执行以下操作:(简化,显然)
任何线程都可以随时处于此过程的任何步骤,并且当涉及共享资源时,它们可以相互踩踏。在读取x和写回x之间的时间内,x的状态可以由另一个线程改变。 假设一个线程检索x的值,但尚未存储它。另一个线程也可以检索相同的x值(因为还没有线程改变它),然后它们都将相同的值(x + 1)存储回x! 例:
通过在访问共享资源的代码之前使用某种锁定机制可以避免竞争条件:
在这里,答案每次都是50,000,000。 有关锁定的更多信息,请搜索:互斥锁,信号量,临界区,共享资源。
你计划在下午5点去看电影。您可以在下午4点查询门票的可用性。该代表说他们可以使用。您可以在演出前5分钟放松并到达售票窗口。我相信你可以猜到会发生什么:这是一个完整的房子。这里的问题是检查和行动之间的持续时间。你在4点询问并在5点采取行动。与此同时,其他人抓住了门票。这是一种竞争条件 - 特别是竞争条件下的"检查然后行动"情景。
宗教代码审查,多线程单元测试。没有捷径。这个Eclipse插件很少出现,但还没有稳定。
最好的方法是创建无副作用和无状态函数,尽可能使用不可变的函数。但这并非总是可行的。因此,使用java.util.concurrent.atomic,并发数据结构,正确的同步和基于actor的并发性将有所帮助。 最佳的并发资源是JCIP。您还可以在此处获得有关上述说明的更多详细信息。 种族条件和数据竞赛之间存在重要的技术差异。大多数答案似乎都假设这些术语是等价的,但事实并非如此。 当2个指令访问相同的存储器位置时发生数据竞争,这些访问中的至少一个是写入,并且在这些访问中进行排序之前没有发生。现在,在排序之前构成一个事件的问题会受到很多争论,但一般来说,同一个锁变量上的ulock-lock对和同一个条件变量上的等待信号对会导致一个先发生的顺序。 竞争条件是语义错误。这是导致错误的程序行为的事件的时间或顺序中发生的缺陷。 许多竞争条件可能(实际上是)由数据竞争引起,但这不是必需的。事实上,数据竞赛和竞争条件既不是必要的,也不是彼此的充分条件。这篇博文还通过简单的银行交易示例很好地解释了这种差异。这是另一个解释差异的简单例子。 现在我们确定了术语,让我们尝试回答原始问题。 鉴于竞争条件是语义错误,没有检测它们的一般方法。这是因为在一般情况下无法使用能够区分正确与不正确程序行为的自动化oracle。种族检测是一个不可判定的问题。 另一方面,数据竞赛具有精确的定义,不一定与正确性相关,因此可以检测它们。有许多种类的数据竞争检测器(静态/动态数据竞争检测,基于锁定的数据竞争检测,基于发生的数据竞争检测,混合数据竞争检测)。最先进的动态数据竞争检测器是ThreadSanitizer,它在实践中运行良好。 处理数据竞争通常需要一些编程规则来诱导在共享数据访问之前发生 - 在开发期间或使用上述工具检测到它们之后。这可以通过锁,条件变量,信号量等来完成。但是,也可以采用不同的编程范例,如消息传递(而不是共享内存),以避免构造中的数据争用。 一种规范的定义是"当两个线程同时访问内存中的相同位置时,并且至少一个访问是写入。"在这种情况下,"reader"线程可能会获得旧值或新值,具体取决于哪个线程"赢得比赛"。这并不总是一个事实,一些真正有毛的低级算法是故意这样做的,但通常应该避免。 @Steve Gury给出了一个很好的例子,它可能是一个问题。 竞争条件是一种只在某些时间条件下发生的错误。
例: 在线程A中:
在线程B中:
如果线程A在检查到object.a不为空之后被抢占,则B将执行 只有当线程A在if语句之后被抢占时才会发生此错误,这种情况非常罕见,但它可能会发生。 竞争条件不仅与软件有关,而且与硬件有关。实际上这个术语最初是由硬件行业创造的。 根据维基百科:
理解这个术语的软件行业没有修改,这使得它有点难以理解。 您需要进行一些替换以将其映射到软件世界:
因此,软件行业的竞争条件意味着"两个线程"/"两个进程"相互竞争"影响某些共享状态",共享状态的最终结果将取决于一些微妙的时序差异,这可能是由某些特定的线程/进程启动顺序,线程/进程调度等 竞争条件发生在多线程应用程序或多进程系统中。最基本的竞争条件是假设两个不在同一个线程或过程中的事物将按特定顺序发生,而不采取措施确保它们这样做。当两个线程通过设置和检查类都可以访问的成员变量来传递消息时,通常会发生这种情况。当一个线程调用sleep以给另一个线程时间来完成一个任务时,几乎总是存在竞争条件(除非该休眠处于循环中,具有一些检查机制)。 用于防止竞争条件的工具取决于语言和操作系统,但是一些常见的工具是互斥锁,关键部分和信号。当你想要确保你是唯一一个做某事的人时,互斥体是好的。当你想确保其他人已经完成某些事情时,信号很好。最小化共享资源还可以帮助防止意外行为 检测竞争条件可能很困难,但有几个迹象。严重依赖睡眠的代码容易出现竞争条件,因此请首先检查受影响代码中的睡眠呼叫。添加特别长的睡眠也可以用于调试以尝试强制特定的事件顺序。这可以用于重现行为,看看是否可以通过改变事物的时间使其消失,以及测试解决方案。调试后应该删除睡眠。 但是,如果存在仅在某些机器上间歇性地发生的问题,那么签名符号就是竞争条件。常见的错误是崩溃和死锁。通过日志记录,您应该能够找到受影响的区域并从那里开始工作。 竞争条件是并发编程的情况,其中两个并发线程或进程竞争资源,结果最终状态取决于谁首先获取资源。 微软实际上发布了一篇关于竞争条件和死锁问题的非常详细的文章。其中摘要最多的摘要是标题段落:
当过程严重依赖于其他事件的顺序或时间时的情况。
例如,
有一些工具可以自动检测竞争条件:
竞争条件可以由Mutex或Semaphores处理。它们充当锁定允许进程基于某些要求获取资源以防止竞争条件。
有各种方法来预防竞争条件,例如关键部分规避。 以下是经典的银行账户余额示例,它将帮助新手轻松了解Java中的线程w.r.t.比赛条件:
竞争条件是当设备或系统试图同时执行两个或多个操作时发生的不期望的情况,但是由于设备或系统的性质,操作必须以正确的顺序进行以便是做得对。 在计算机存储器或存储器中,如果几乎在同一时刻接收到读取和写入大量数据的命令,则机器会尝试覆盖部分或全部旧数据,而旧数据仍在读。结果可能是以下一种或多种:计算机崩溃,"非法操作",程序通知和关闭,读取旧数据的错误或写入新数据的错误。 如果使用"原子"类,则可以防止竞争条件。原因只是线程没有单独的操作get和set,例如如下:
因此,您将在链接"ai"中有7个。 竞争条件是当两个或多个进程可以同时访问和更改共享数据时发生的不良情况。发生这种情况是因为存在对资源的冲突访问。临界区问题可能会导致竞争状况。为了解决过程中的关键条件,我们一次只取出一个执行临界区的过程。 你并不总是想放弃竞争条件。如果你有一个可以被多个线程读取和写入的标志,并且这个标志被一个线程设置为'done',那么当flag设置为'done'时其他线程停止处理,你不希望那个"比赛"条件"被淘汰。事实上,这个可以被称为良性竞争条件。 但是,使用检测竞争条件的工具,它将被视为有害的竞争条件。 有关种族状况的更多详细信息,请访问http://msdn.microsoft.com/en-us/magazine/cc546569.aspx。 考虑一旦计数增加就必须显示计数的操作。即,一旦CounterThread递增值,??DisplayThread就需要显示最近更新的值。
产量
这里CounterThread经常获取锁定并在DisplayThread显示之前更新值。这里存在种族条件。竞争条件可以通过使用Synchronzation来解决 尝试这个基本示例以更好地了解竞争条件:
|
最新内容
相关内容
如何杀死一个Python线程
如何杀死一个Python线程,状态,线程,代码,标准,意外,工作,控制权,培训,事件,结束,我经常被问到如何杀死一个后台线程,这个问题的答案让很多人不Python学习之进程和线程
Python学习之进程和线程,代码,平台,系统,线程,进程,标准,数据,服务,培训,管理,对于操作系统来说,一个任务就是一个进程(Process),比如打开一个Python实现线程安全的单例模式
Python实现线程安全的单例模式,代码,系统,信息,地方,设计,培训,实例,线程,模式,存在,单例模式是一种常见的设计模式,该模式的主要目的是确保某Python线程编程的两种方式
Python线程编程的两种方式,代码,包装,线程,培训,函数,对象,模块,参数,方式,方法,Python中如果要使用线程的话,python的lib中提供了两种方式。Python 多线程死锁问题的巧妙解决
Python 多线程死锁问题的巧妙解决方法,异常,持有,代码,情况,信息,管理,数据,包装,策略,预期,死锁死锁的原理非常简单,用一句话就可以描述完。Python进程、线程、协程的区别
Python进程、线程、协程的区别,地址,单位,线程,入口,状态,培训,进程,区别,资源,空间,简述进程、线程、协程的区别以及应用场景?线程是指进程python线程同步(锁)
python线程同步(锁),状态,数据,情况,线程,培训,通信,暂停,概念,异常,条件,多线程的优势在于可以同时运行多个任务(至少感觉起来是这样)。但是Python 条件对象
Python 条件对象,状态,培训,对象,条件,线程,方法,底层,发生,场景,典型,条件对象总是与某种类型的锁对象相关联,锁对象可以通过传入获得,或者在Python 线程对象
Python 线程对象,线程,名称,单位,时间,培训,对象,程序,参数,方法,函数,先了解一下Python守护线程基本概念。守护线程:当一个线程被标记为守护python 的条件判断语句
python 的条件判断语句,代码,培训,语句,条件,冒号,整数,序列,函数,逻辑,元素,条件判断if语句(注意不要少写了冒号:。)if:elif:elif:Elseif语python多线程和多进程之间的联系
python多线程和多进程之间的联系,进程,培训,通信,标准,管理,代理,线程,模块,之间,全部,关于多线程的大概讲解:在Python的标准库中给出了2个模python怎样终止线程
python怎样终止线程,培训,线程,方法,定义,以上,更多,内容,在python中启动和关闭线程:一、启动线程首先导入threadingimportthreading然后定