CN113360302A - 一种耗时操作取消及阻塞异步转换的方法及系统 - Google Patents
一种耗时操作取消及阻塞异步转换的方法及系统 Download PDFInfo
- Publication number
- CN113360302A CN113360302A CN202110911090.XA CN202110911090A CN113360302A CN 113360302 A CN113360302 A CN 113360302A CN 202110911090 A CN202110911090 A CN 202110911090A CN 113360302 A CN113360302 A CN 113360302A
- Authority
- CN
- China
- Prior art keywords
- thread
- time
- function
- semaphore
- consuming operation
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Granted
Links
Images
Classifications
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F9/00—Arrangements for program control, e.g. control units
- G06F9/06—Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
- G06F9/46—Multiprogramming arrangements
- G06F9/54—Interprogram communication
- G06F9/546—Message passing systems or structures, e.g. queues
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F9/00—Arrangements for program control, e.g. control units
- G06F9/06—Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
- G06F9/46—Multiprogramming arrangements
- G06F9/54—Interprogram communication
- G06F9/543—User-generated data transfer, e.g. clipboards, dynamic data exchange [DDE], object linking and embedding [OLE]
Landscapes
- Engineering & Computer Science (AREA)
- Software Systems (AREA)
- Theoretical Computer Science (AREA)
- Physics & Mathematics (AREA)
- General Engineering & Computer Science (AREA)
- General Physics & Mathematics (AREA)
- Debugging And Monitoring (AREA)
Abstract
本发明公开了一种耗时操作取消及阻塞异步转换的方法,包括:创建耗时操作线程;为耗时操作线程建立二状态信号量;任意线程将二状态型号量状态修改为有信号以发出取消请求;耗时操作线程通过监听或查询二状态信号量状态来检测取消;同时本发明还可以将任意阻塞函数转换为异步函数或UI阻塞函数来使用。本发明一种耗时操作取消及阻塞异步转换的方法及系统,取消请求与阻塞异步转换均具有业务无关性。只需要用统一的接口向执行耗时操作的线程发出取消请求,不需要针对不同业务、对象、操作提供专用的取消接口。耗时操作实现只需要提供阻塞接口,不需要提供异步和UI阻塞接口。
Description
技术领域
本发明涉及线程处理技术,具体涉及一种耗时操作取消及阻塞异步转换的方法及系统。
背景技术
软件中大量涉及耗时操作,如设备IO、通信IO、大计算等。这些操作需要耗费一定时间,且完成时间取决于系统与网络状况等因素,具有一定的不确定性。GUI SDK一般工作于单线程模式,如Windows GUI、Android GUI、QT GUI等皆如此。在GUI App(图形用户界面应用程序)中,UI线程(处理GUI的线程)负责监听和分发UI消息(GUI消息),使得GUI能接受用户的界面输入。因此UI线程不能直接执行耗时操作,否则用户的输入将不能被UI线程及时分发和处理,呈现界面卡顿或长时间僵死现象。CPU一般包含多个核心,为了充分发挥CPU的性能,有时希望让多个耗时操作并发执行。耗时操作函数一般提供两种接口,阻塞接口和异步接口,分别对应于阻塞模式和异步模式。阻塞接口会阻塞执行线程,直到操作完成后才返回。异步接口不等操作结束即返回,操作完成后通过事件、消息、回调等方式通知异步调用的发起者。
在现有的取消技术中,取消与操作或对象关联。取消与操作关联指,为特定耗时操作提供对应的取消接口。例如为耗时操作接口read提供取消接口readCancel。取消与对象关联指,提供了多个耗时操作接口的对象,对外提供一个统一的接口来取消该对象上所有正在执行的任意耗时操作。例如WindowsIoCancel接口可用来取消指定内核对象上,由当前线程发起的,所有正在异步执行的任意类型的IO操作。这种方法的主要缺陷是,取消与业务相关。需要为每种耗时操作或对象提供取消接口,在发出取消请求时,需要根据当前执行的操作或对象,调用对应的接口发出取消请求。如果一个大粒度耗时操作函数func调用了多个耗时操作接口,或多个对象的耗时操作接口,App在发出取消请求时,无法确定应该向哪个操作或那个对象发出取消请求。要解决这个问题,就需要为该func提供取消接口,在取消接口函数中根据该func的状态向对应操作或对象发出取消请求。显然,该取消函数实现并不简单,且针对每种这样的大粒度耗时操作函数都要提供对应的取消接口,代价很高。
用一个Windows下的具体案例来展示这种技术的缺陷。函数download从服务器下载文件并保存到文件系统。download函数以异步模式循环调用ReadFile接收网络数据;对于接收到的每一块数据,以异步模式调用WriteFile将其写入到文件中。download函数维护一组状态以标识其正在对哪个句柄执行IO操作。为download实现配套的取消接口downloadCancel,它根据download维护的状态选择对应的句柄对其发起CancelIo请求。
除此之外,现有的这类取消技术,一般只适用于异步IO。这就要求App实现的耗时操作函数以异步方式组织逻辑,相对于用阻塞模式顺序组织逻辑,异步模式代价会高得多。
在现有异步实现技术中,当耗时操作提供者只提供了阻塞接口时,异步接口需要由App创建线程来实现。无论App基于阻塞接口实现异步支持,还是耗时操作提供者实现异步接口,都涉及线程创建/申请,在后台线程中执行阻塞函数,多线程竞争处理,完成通知等技术环节。且由于逻辑相似,往往会产生大量相似但不相同的代码。
在现有异步实现技术中,存在完成通知方式不统一的问题。软件一般会使用第三方组件,有的组件只提供了阻塞接口,有的组件还提供了异步接口。App基于阻塞接口实现异步接口所采用的完成通知方式,以及不同提供商提供的异步接口所定义的完成通知方式上往往不同。这为App开发引入额外负担。
现有耗时操作处理技术一般没有提供UI线程可直接调用的阻塞接口,而这种方式对于某些应用场景可大幅度简化App的实现。
综上现有耗时操作取消及异步支持技术,存在诸多缺陷,使得耗时操作在实现和使用上都存在复杂度和代价较高的问题。耗时操作的取消和异步支持技术也是长期以来困扰行业的技术痛点。
发明内容
本发明所要解决的技术问题是现有的耗时操作相关技术具有复杂度高,取消流程冗长,并且会造成开发的额外负担,目的在于提供一种耗时操作取消及阻塞异步转换的方法及系统,解决上述问题。
本发明通过下述技术方案实现:
一种耗时操作取消及阻塞异步转换的方法,包括:创建耗时操作线程,并将所述耗时操作线程异步运行于后台;为所述耗时操作线程建立二状态信号量,所述二状态信号量的状态包括有信号和无信号;当任意线程对所述耗时操作进行取消时,将所述二状态信号量的状态修改为有信号;所述耗时操作线程监听或查询到所述二状态信号量的状态为有信号时,取消所述耗时操作。
在现有技术中,Windows自Vista开始提供了一种阻塞IO取消技术。Windows提供了CancelSynchronousIo API,可用来对指定线程正在执行的任意阻塞IO操作发出取消请求。这种方法提供了业务无关性,发出请求时,不用关心正在执行的是何种IO操作,只需要向执行IO操作的线程发出取消请求即可。这种方法的主要缺陷是只能对正在执行的IO操作发出取消请求。如果当前未在执行IO操作,调用CancelSynchronousIo()会失败,且此后执行IO操作不会检测到取消,即取消请求不会被缓存。对于要执行IO操作的耗时操作函数func,除了执行IO操作外,还会执行其他逻辑处理。发出取消请求时,App并不知道func当前是否正在执行IO操作。解决这个问题代价较高。一种解决方法是:为func定义一组状态,LOGIC、IO、END,分别表示正在执行非IO逻辑操作,正在执行IO操作,func操作结束。发出取消请求时,根据func的执行状态分别处理:当状态为IO时,调用CancelSynchronousIo()发出取消请求;当状态为END时,放弃取消请求;当状态为LOGIC时,循环(中间可间歇性休眠)检测状态,直到状态变更为IO或END,并做对应处理。除此之外,还存在一些临界条件需要更细致的处理,例如func在IO操作完成后设置状态为LOGIC,而func检测到IO操作完成要滞后于平台内核实际的IO操作完成。除此之外,CancelSynchronousIo取消技术只针对IO操作,取消检测由内核态驱动程序负责,App中不能检测取消,也因此,在App实现的大计算中不能应用此取消方法。正由于存在上述缺陷,这种技术应用不广,支持的驱动程序也很少。Windows网络IO、文件系统、网络文件系统等驱动程序均未支持。
本发明与现有技术相比,具有如下的优点和有益效果:
本发明一种耗时操作取消及阻塞异步转换的方法及系统,取消请求具有业务无关性,无论执行的是何种耗时操作或组合,App都只需要用统一的接口,向执行耗时操作的线程发起取消请求,不需要针对不同业务、对象、操作提供专用的取消接口,避免了现有技术需要调用业务相关接口来发起取消请求的缺陷。取消请求只是设置取消信号量为有信号,取消请求自带缓存属性。App可以随时发出取消请求,无论此时耗时操作是否正在检测取消信号量状态。即便发出取消请求时,耗时操作未在检测取消信号量状态,此后一旦其检测取消信号量状态,就能检测到被缓存的取消请求。避免了现有CancelSynchronousIo取消技术只能对正在执行的IO操作发出取消请求的缺陷。
同时本发明实施例可以调用任意数量,任意层次的cblock函数,以形成大粒度cblock函数。且无需为该大粒度cblock函数提供配套的取消接口。避免了现有技术一般需要为大粒度耗时操作函数提供配套取消接口的缺陷。
cblock是阻塞函数,这使得在实现大粒度cblock函数时,可以用顺序逻辑调用其他cblock函数。而现有取消技术一般只适用于有异步接口,为了支持取消,需要以异步方式组织逻辑。周知的,同样的业务,用阻塞方式顺序组织逻辑,相对于用异步方式组织逻辑,复杂度要低得多。
调用链最底层的cblock函数一般会调用IO等平台耗时操作API,并等待其完成。这些平台API不是cblock函数,可以基于平台API的特点,对其改造或封装,使之能在阻塞等待操作完成的同时检测取消。在OS内核实施本方案时,可改造平台耗时操作阻塞模式API为cblock函数;在应用层实施本方案时,可实现一封装层(简称“平台封装层”),将平台API封装为cblock函数。无论是改造还是封装,其原理都是在阻塞等待IO等耗时操作完成的同时监听取消事件。
改造或封装的平台cblock API在原型和语义上与对应平台API保持一致,其差异仅在于前者支持本取消方法。这种接口上的兼容性带来如下有益效果:
本发明实施于平台内核时,调用平台异步API的现有App代码不受取消支持模块的任何影响,因为平台API改造只针对平台阻塞API,不会改造平台异步API。
本发明实施于平台内核时,调用平台阻塞API的现有App代码可以获得兼容支持,且几乎无需任何修改就能自然获得取消支持。当对执行现有代码的cthread发出取消请求时,现有代码调用的平台阻塞API能检测取消,并返回失败,错误码被设置为取消错误码,绝大多数现有代码的错误处理都能兼容这种情况,将取消错误码作为其它或未知错误处理。
本发明实施于应用层时,平台cblock API的函数名称与对应平台API的有差异,对现有App代码不产生任何影响。要将现有耗时操作阻塞函数改造为cblock函数,只需要将调用的平台API名称替换为对应的cblock API名称即可。其道理与上述实施于平台内核时,调用平台阻塞API的现有代码能自然获得取消支持相同。
改造或封装平台API为平台cblock API后,绝大多数情况下,App在实现cblock函数时,不需要直接检测取消信号量状态。绝大多数cblock函数,最终都会直接或间接地调用平台cblock API,平台cblock API会检测取消,检测到取消后,通过取消错误码向外层传递。cblock函数一般不需要对其调用的cblock函数返回的取消错误码做针对性处理,而将其视为一种不可恢复的其它错误来处理。这些支持可以简化大粒度cblock函数的实现。
本取消方法即可在应用层实施,也可在平台内核实施。在平台内核实施时,调用平台阻塞API的现有App代码几乎无需任何修改就能自然获得取消支持,效果最佳。
而在本发明实施阻塞异步转换时,耗时操作只需要提供标准阻塞接口,不需要提供异步接口。阻塞函数的实现只关注业务逻辑,不关心App以异步还是阻塞方式使用它。按本方案实现的异步阻塞支持模块与业务无关,其转换工具函数可将任意阻塞函数转换为异步函数、UI阻塞函数来使用。统一了异步函数的完成通知方式。线程竞争处理屏蔽在异步阻塞支持模块内部,App和耗时操作实现均不用关注。
本发明引入的UI阻塞模式,对特定应用场景,可大幅度简化App开发。例如:函数download从服务器下载文件并保存到文件系统,其实现为阻塞函数。UI线程弹出带取消按钮的指示窗口,然后调用blk_to_ublk(),将download转换为UI阻塞函数来使用。它会阻塞UI线程但可分发UI消息。download执行期间,UI线程检测到用户点击取消按钮事件后,调用ublk_cancel()发出取消请求。
得益于本发明的取消方法,异步和UI阻塞函数的取消支持与业务无关。无论执行的是何种异步和UI阻塞操作,App均通过不依赖业务的取消接口发出取消请求。
附图说明
此处所说明的附图用来提供对本发明实施例的进一步理解,构成本申请的一部分,并不构成对本发明实施例的限定。在附图中:
图1为本发明实施例一种耗时操作取消及阻塞异步转换的方法步骤示意图;
图2为本发明实施例一种耗时操作取消及阻塞异步转换的系统结构示意图;
图3为本发明实施例blk_to_async()工作流程示意图;
图4为本发明实施例blk_to_ublk()工作流程示意图。
具体实施方式
为使本发明的目的、技术方案和优点更加清楚明白,下面结合实施例和附图,对本发明作进一步的详细说明,本发明的示意性实施方式及其说明仅用于解释本发明,并不作为对本发明的限定。
实施例
请结合参阅图1,为本发明实施例所提供的一种耗时操作取消及阻塞异步转换的方法的流程示意图,所述一种耗时操作取消及阻塞异步转换的方法可以应用于图2中的一种耗时操作取消及阻塞异步转换的系统,进一步地,所述一种耗时操作取消及阻塞异步转换的方法具体可以包括以下步骤S1-步骤S4所描述的内容。
一种耗时操作取消及阻塞异步转换的方法,包括:
S1:创建耗时操作线程,并将所述耗时操作线程异步运行于后台;
S2:为所述耗时操作线程建立二状态信号量,所述二状态信号量的状态包括有信号和无信号;
S3:当任意线程对所述耗时操作进行取消时,将所述二状态信号量的状态修改为有信号;
S4:所述耗时操作线程监听或查询到所述二状态信号量的状态为有信号时,取消所述耗时操作。
在本实施例实施时,不同于现有技术的取消方式,本实施例中采用了二状态信号量作为取消信号量来表征耗时操作线程是否需要取消。本发明实施例引入可监听的,与线程关联的取消信号量,用来衔接线程和耗时操作的取消传递。通过设置执行耗时操作线程的取消信号量为有信号来向线程发出取消请求,耗时操作代码通过查询或监听当前线程的取消信号量状态来检测取消。
在一个实施例中,创建耗时操作线程,并将所述耗时操作线程异步运行于后台包括:
创建耗时操作线程时,将对阻塞函数的一次调用的信息打包进函数对象中;
通过第一异步支持模块创建耗时操作线程,所述耗时操作线程调用并执行所述函数对象;
通过第二异步支持模块在监听耗时操作线程完成操作的同时监听并分发UI消息,并响应UI操作;
当所述耗时操作线程调用执行所述函数对象,并待其返回后发出完成通知;
使用所述函数对象中记录的完成通知方式和附加信息发出完成通知;所述完成通知方式和所述附加信息由App在发起异步请求时指定。
在本实施例实施时,耗时操作只需要提供标准阻塞接口,不需要提供异步接口。阻塞函数的实现只关注业务逻辑,不关心App以异步还是阻塞方式使用它。
在本实施例中,引入“函数对象”的概念,函数对象存储“对具体阻塞函数一次调用”的相关信息,包括阻塞函数地址,调用阻塞函数时传入的实际参数等。函数对象在执行时调用该阻塞函数地址对应的函数,传入函数对象中存储的对应参数。
多数现代程序语言支持闭包。闭包是一个实现函数式接口的对象,在闭包中可以使用外部环境的变量。闭包一般通过lambda表达式或匿名函数创建。在闭包中,使用外部环境变量,调用阻塞函数,这样的闭包就是本方法所需函数对象,它包含了对阻塞函数一次调用的全部信息。
对于不支持闭包的程序语言,可以针对每个阻塞函数接口,手动实现函数对象(闭包)。其实现只依赖阻塞函数的接口,不依赖其业务逻辑,可按模版书写,也可以实现工具软件来自动生成函数对象代码。
在一个更具体的实施例中,引入异步协调类CnsAsync。它记录一次异步调用的相关信息,如阻塞函数的返回值、错误码、完成通知方式及附加信息等,并提供取消、完成通知等接口。用户线程和异步线程通过CnsAsync对象来交互,例如,异步线程可通过CnsAsync对象通知用户线程操作完成,用户线程可通过CnsAsync对象向异步线程发出取消请求等。
在一个更具体的实施例中,实现独立于业务的工具函数blk_to_async(),将任意阻塞函数转换为异步函数来使用。它创建异步线程,让异步程执行函数对象。其核心是:将“对具体阻塞函数一次调用”信息打包到函数对象中,推迟到由异步线程来执行,从而达到将阻塞函数转换为异步函数的目的。App创建“对具体阻塞函数一次调用”的函数对象,调用blk_to_async(),传入该函数对象,即可发起关于该阻塞函数的异步调用。
在一个更具体的实施例中,实现独立于业务的工具函数blk_to_ublk(),将任意阻塞函数转换为UI阻塞函数来使用。它调用blk_to_async()或用相同的方法发起异步请求,在等待异步操作完成的同时监听并分发UI消息,从而实现将阻塞函数转换为UI阻塞函数的目的。App创建“对具体阻塞函数一次调用”的函数对象,调用blk_to_ublk(),并传入该函数对象,即可发起关于该阻塞函数的UI阻塞调用。实现blk_to_ublk()的关键是,在等待异步操作完成的同时监听并分发UI消息。在实施本发明时,可根据平台的支持选择恰当的方式来实现该关键点。例如,对Windows,可用MsgWaitForMultipleObjects()来等待异步操作完成的同时监听并分发UI消息;对QT,可用QEventLoop执行消息循环以分发UI消息,通过引发QT信号来通知操作完成,在该信号的处理槽函数中终止QEventLoop消息循环。
在一个更具体的实施例中,异步线程调用函数对象执行耗时操作,并待其返回后,将错误码保存到对应CnsAsync实例中。对于UI阻塞请求,blk_to_ublk()检测到完成通知后,将对应CnsAsync实例中记录的,由异步线程设置的,对应阻塞函数返回的错误码,赋值给当前线程的错误码变量。
App通过blk_to_async()发起的异步请求完成后,从对应CnsAsync实例获得错误码。App通过blk_to_ublk()发起的UI阻塞请求完成后,按平台常规方式获得错误码。不同阻塞函数指示操作成功或错误的方式是不同的。因此异步线程不对操作成功或失败做判断,仅简单地获取线程相关错误码,将其保存到对应CnsAsync实例中。平台API返回的错误码一般是线程相关的,如Linux和WIndowsAPI分别通过线程相关errno和GetLastError()返回错误码。而阻塞函数由异步线程执行,用户线程无法直接获得其返回的线程相关错误码,因此需要由异步线程将其保存到CnsAsync中,供用户线程访问。返回错误码的理想方式是通过函数返回值,将函数返回值定义为整数类型,返回非负整数表示成功,返回负数表示失败,负数的绝对值表示错误码。这时不需要用另外的方式来返回和保存错误码。但为了兼容现有的阻塞函数,可在CnsAsync中保存单独的错误码。
在一个更具体的实施例中,根据具体实施平台的特点定义一组完成通知方式。如消息(如Windows消息)、事件(如Windows Event、Linux eventfd、QT信号)、回调函数等完成通知方式。对于回调通知方式,最佳实践是让回调函数由用户线程执行,而不是由异步线程执行。
在一个更具体的实施例中,异步线程调用函数对象执行耗时操作,并待其返回后,调用对应CnsAsync实例的完成通知接口发出完成通知。CnsAsync完成通知接口函数使用对象中记录的,App在发起异步请求时指定的完成通知方式及附加信息发出完成通知,如发送消息、设置事件为有信号、发起回调等。
在一个更具体的实施例中,当需要支持取消时,采用本发明的取消方法。此时异步线程应创建为cthread类型,阻塞函数应实现为cblock函数。App调用blk_to_async()发出异步请求后,通过对应CnsAsync实例的取消接口发出取消请求。CnsAsync取消接口从对象中获得异步线程ID,调用cthread_cancel()向异步线程发出取消请求。阻塞函数负责检测取消,检测到取消后返回取消错误码。异步线程不需要对取消错误码做针对性处理,仅将其视为一种错误,按正常方式将错误码保存到CnsAsync实例中。可实现独立于业务的工具函数ublk_cancel(),以请求取消当前线程正在执行的UI阻塞操作。其实现方法为,获得UI阻塞操作对应的CnsAsync实例,调用其取消接口发出取消请求。UI线程调用blk_to_ublk()发出UI阻塞请求后,需要时用ublk_cancel()发出取消请求。为提供对UI阻塞请求的取消支持,对应CnsAsync实例应对发起UI阻塞请求的用户线程可见。通常将CnsAsync实例引用存储到TLS(线程局部存储)中。ublk_cancel()通过TLS获得当前线程正在使用的CnsAsync实例。需要支持UI阻塞嵌套时,可用堆栈来存储一个UI线程正在执行的所有UI阻塞操作的对应CnsAsync实例,并将该堆栈引用存储到TLS中。
请参阅图3,本实施例示出了blk_to_async()工作流程,虚线框内为blk_to_async()实现逻辑示意图。图中未示出取消流程。需要取消时,用户线程调用async取消接口发出取消请求。大多数线程库定义的线程入口函数只接受一个参数。可将IFuncObj保存到CnsAsync实例中,只把CnsAsync实例传递给线程入口函数。
请参阅图4,本实施例示出了blk_to_ublk()工作流程,虚线框内为blk_to_ublk()实现逻辑示意图。图中未示出取消流程。需要取消时,用户线程调用ublk_cancel()发出取消请求。大多数线程库定义的线程入口函数只接受一个参数。可将IFuncObj保存到CnsAsync实例中,只把CnsAsync实例传递给线程入口函数。图中“创建CnsAsync实例async并保存”,其保存指将async引用保存到TLS中。图中“为当前线程设置错误码”,是指将async中存储的错误码用平台约定的方式赋值给当前线程。如对Linux,可直接赋值给线程相关errno,对Windows,可调用SetLastError()赋值。
在上述实施例中,通过异步支持模块进行异步支持,异步支持模块包括CnsAsync、工具函数blk_to_async()、工具函数blk_to_ublk()和工具函数ublk_cancel()。
在一个更具体的实施例中,通过第一异步支持模块和第二异步支持模块实现阻塞异步转换,其中,第一异步支持模块将阻塞函数一次调用信息打包进函数对象中;异步函数创建耗时操作线程,所述耗时操作线程调用并执行所述函数对象;而第二异步支持模块调用第一异步支持模块发起异步请求,在等待异步操作完成的同时监听并分发UI消息,将阻塞函数转换为UI阻塞函数。
优选的,第一异步支持模块采用工具函数blk_to_async(),而第二异步支持模块采用工具函数blk_to_ublk()。
在一个实施例中,多个所述耗时操作线程对应的二状态信号量被存储于全局表中;
任意线程通过所述全局表获取所述耗时操作线程对应的二状态信号量。
本实施例实施时,全局存储取消信号量,应当理解的是,在本申请中出现的二状态信号量与取消信号量是等同的。使任意线程都能通过线程ID(或句柄,下同)查询到指定线程的取消信号量。在应用层实施本发明时,可定义key为线程ID,value为取消信号量的全局map表。程序通过线程ID在该表中查询指定线程的取消信号量。在平台内核中实施本发明时,取消信号量可定义为线程对象的属性,存储线程对象的表可视为存储取消信号量的全局表,此时不需要额外引入表。在应用层实施本发明时,如果平台支持,可将取消信号量额外存储为TLS(线程局部存储),耗时操作代码可以无锁方式获得当前线程的取消信号量,不用加锁查询全局表,避免性能损失。
在一个实施例中,每一个耗时操作线程对应至少一个阻塞函数;
一个阻塞函数可以调用任意数目,任意层次的子阻塞函数,形成大粒度阻塞函数;
在所述大粒度阻塞函数的任意子阻塞函数中通过查询或监听获取对应所述耗时操作线程的二状态信号量为有信号,或通过子阻塞函数返回的错误码检测到操作被取消时,所述子阻塞函数通过错误码向外层函数指示操作被取消,直至最外层阻塞函数。
本实施例实施时,关联了取消信号量,且其取消信号量能被任意线程查询到的线程,称为cthread。可以在线程被创建时是立刻创建并全局存储取消信号量,也可以在使用取消信号量时(向目标cthread发出取消请求、获取当前线程的取消信号量)再创建并全局存储取消信号量。前者简称为“取消信号量在线程启动时创建”方式,后者简称为“取消信号量按需创建”方式。无论采用哪种方式,在线程终止时,都应将取消信号量从全局存储中移除并销毁。当耗时操作函数检测到取消后,通过函数返回值,或线程相关errno,或GetLastError()函数等方式返回约定的取消错误码。
能通过查询或监听当前线程取消信号量状态检测取消,或/和通过其调用的函数返回的取消错误码检测取消的阻塞函数称为cblock函数。cblock函数具有如下特征:
cblock函数总是由cthread执行,因为只有cthread才会关联取消信号量。
cblock函数是阻塞函数,它会一直运行(如大计算),或/和等待IO等耗时操作完成,或/和等待其调用的其它cblock函数返回。
cblock函数可以调用任意数目,任意层次的cblock子函数,以形成更大粒度的cblock函数。
调用链最底层的cblock函数通过查询或监听当前线程取消信号量检测取消。非调用链最底层的cblock函数既可以通过其调用的cblock子函数返回的取消错误码检测取消,也可以直接查询或监听当前线程取消信号量以检测取消,二者不是排他关系,可以并存。
当cblock函数通过查询或监听当前线程的取消信号量检测到取消事件,并做相应处理后,返回取消错误码,向外层cblock函数指示操作被取消。外层cblock函数检测到取消错误码,并做相应处理后,返回取消错误码,向更外层cblock函数指示操作被取消。如此递归,直到最外层cblock函数。因此,对于包含任意数目,任意层次cblock子函数的大粒度cblock函数,在任意cblock子函数中检测到取消事件,都能将取消错误码逐层向上返回,直到最外层cblock函数。
在本实施例中,可以创建临时线程来执行耗时操作,操作完成后即销毁线程。也可以从线程池中分配线程来执行耗时操作,操作完成后将线程释放回线程池中。对于从线程池分配线程来执行耗时操作:可以先将线程池中的所有线程初始化为cthread,从线程池中分配线程后,在执行耗时操作前设置当前线程的取消信号量为无信号;也可以从线程池中分配线程后,在执行耗时操作前将当前线程初始化为cthread,在耗时操作完成后将当前线程去初始化为非cthread。
在应用层实施时,如果采用“取消信号量在线程启动时创建”方式,在创建cthread后,需要等待cthread完成取消信号量创建及全局存储等初始化操作,否则,发出取消请求时,可能因为目标cthread还未完成初始化,而无法获得其取消信号量。也可以在发出取消请求,检测到目标cthread的取消信号量不存时,再同步等待cthread完成初始化。可以根据平台特点选择性能最优的同步等待方式,如使用完成信号量、自旋信号量等方式同步等待。在应用层实施时,如果采用“取消信号量按需创建”方式,在向目标cthread发出取消请求,以及在获取当前线程取消信号量时,都可能会创建取消信号量并全局存储,需要采取恰当的同步措施以确保这种方式的健壮性。同时需要处理好取消请求时,目标线程已经终止的临界问题。
在一个实施例中,还包括,在创建耗时操作线程之前创建取消管理模块;所述取消管理模块被配置为对所述二状态信号量进行管理和支持线程获取所述二状态信号量;
当任意线程对所述耗时操作进行取消时,所述取消管理模块将所述耗时操作线程对应的二状态信号量修改为有信号;
所述取消管理模块支持所述耗时操作线程获取当前线程的二状态信号量,并根据当前线程的二状态信号量状态判断操作是否被请求取消。
本实施例实施时,实现取消管理模块CancelMng。它实现对取消信号量的管理;支持对指定cthread的发起取消请求;支持cthread获得当前线程的取消信号量;支持cthread测试当前线程是否被请求取消,支持将普通线程初始化为cthread,支持App直接创建cthread等。
在平台内核实施本发明时,修改平台内核代码,将相关处理融入到平台内核中,以实现本方案定义的取消管理支持。此时CancelMng只是逻辑上的概念。
CancelMng实现并提供一组API:
cthread_abort_evt():供耗时操作代码获得当前cthread的取消信号量。
cthread_abort_clear():设置当前线程取消信号量为无信号。
cthread_aborted():供耗时操作代码查询当前cthread是否被请求取消。
cthread_cancel():供App向任意cthread发出取消请求。
cthread_create():供App直接创建和启动cthread。
cthread_init():供App将当前线程初始化为cthread。
cthread_exit():供App直接创建cthread。
cancel_mng_init():供App初始化CancelMng。
cancel_mng_exit():供App去初始化CancelMng。
当平台提供了Thread类,如Java的Thread、QT的Qthread等时,可以定义一个代表cthread的类CnsThread。其特征如下:
CnsThread从平台Thread类派生,重写其执行方法,如run(),它相当于线程入口函数。重写的run()方法执行下列逻辑:当采用“取消信号量在线程启动时创建”的方式时,调用cthread_init()初始化当前线程;调用CnsThread定义的抽象方法exec();调用cthread_exit()去初始化当前线程。App用CnsThread来创建cthread时,从CnsThread派生类。在派生类中实现CnsThread定义的exec()方法,它相当于App提供的实际线程入口函数。App创建该派生类实例,调用其启动方法启动线程,启动方法是由平台Thread类提供的。当采用“取消信号量在线程启动时创建”的方式时,CnsThread可以重写平台Thread的启动方法。在重写的方法中调用基类方法启动线程,然后等待新建线程完成初始化。
请参阅图2,基于同样的发明构思,还提供了一种耗时操作取消及阻塞异步转换的系统,所述系统包括创建单元、信号量单元、修改单元和取消单元。
创建单元,被配置为创建耗时操作线程,并将所述耗时操作线程异步运行于后台;
信号量单元,被配置为为所述耗时操作线程建立二状态信号量,所述二状态信号量的状态包括有信号和无信号;
修改单元,被配置为当任意线程对所述耗时操作进行取消时,将所述二状态信号量的状态修改为有信号;
取消单元,所述耗时操作线程监听或查询到所述二状态信号量的状态为有信号时,取消所述耗时操作。
在一个实施例中,创建耗时操作线程时,所述创建单元将对阻塞函数的一次调用的信息打包进函数对象中;
通过第一异步支持模块创建耗时操作线程,所述耗时操作线程调用并执行所述函数对象;
通过第二异步支持模块在监听耗时操作线程完成操作的同时监听并分发UI消息,并响应UI操作;
当所述耗时操作线程调用执行所述函数对象,并待其返回后发出完成通知;
使用所述函数对象中记录的完成通知方式和附加信息发出完成通知;所述完成通知方式和所述附加信息由App在发起异步请求时指定。
在一个实施例中,多个所述耗时操作线程对应的二状态信号量被存储于全局表中;
任意线程通过所述全局表获取所述耗时操作线程对应的二状态信号量。
在一个实施例中,每一个耗时操作线程对应至少一个阻塞函数;
一个阻塞函数可以调用任意数目,任意层次的子阻塞函数,形成大粒度阻塞函数;
在所述大粒度阻塞函数的任意子阻塞函数中通过查询或监听获取对应所述耗时操作线程的二状态信号量为有信号,或通过子阻塞函数返回的错误码检测到操作被取消时,所述子阻塞函数通过错误码向外层函数指示操作被取消,直至最外层阻塞函数。
在一个实施例中,还包括:
取消管理模块,被配置为对所述二状态信号量进行管理和支持线程获取所述二状态信号量;
当任意线程对所述耗时操作进行取消时,所述取消管理模块将所述耗时操作线程对应的二状态信号量修改为有信号;
所述取消管理模块支持所述耗时操作线程获取当前线程的二状态信号量,并根据当前线程的二状态信号量状态判断操作是否被请求取消。
在一个更具体的实施例中,当应用在Linux和Windows应用层实现CancelMng时,定义进程级全局map表abortEvtTab。其key为线程ID(或线程句柄),value为key对应线程的取消信号量引用。
定义互斥锁cancelMngMutex来保护对abortEvtTab的多线程并发访问。对Windows,互斥锁可用Mutex;对Linux,互斥锁可用pthread_mutex_t。
当平台支持TLS时,可用TLS来存储当前线程的取消信号量curAbortEvt。通过TLS,cthread可用无锁方式获得当前线程的取消信号量。当平台不支持TLS时,cthread可通过查询abortEvtTab获得当前线程的取消信号量。
当采用“取消信号量在线程启动时创建”的方式时,本例在线程创建后等待其完成初始化。定义完成通知信号量initSig。create线程创建cthread后,等待initSig有信号;cthread完成初始化后,设置initSig为有信号,从而唤醒create线程。对于Linux,可采用pthread_cond作为initSig;对于Windows,可采用匿名Event作为initSig;当对性能特别敏感时,可以用自旋信号量作为initSig。
CancelMng提供一组API供cblock函数实现和App发起取消、创建cthread使用。CancelMngAPI实现逻辑和用途描述如下。
初始化CancelMng:function cancel_mng_init();
进程启动后,App在调用CancelMng其他接口前调用此函数。
此函数完成abortEvtTab及cancelMngMutex的创建等取消支持模块初始化操作。
去初始化CancelMng:function cancel_mng_exit();
进程终止前,App调用此函数,此后不得再调用CancelMng其它函数。
此函数完成abortEvtTab及cancelMngMutex的销毁等取消支持模块去初始化操作。
发起对指定cthread的取消请求:function cthread_cancel(cthreadId);
App调用此函数发起对指定cthread的取消请求。
此函数用cthreadId在abortEvtTab中查询得到对应线程的取消信号量,设置其状态为有信号。
当采用“取消信号量按需创建”的方式时,在cancelMngMutex锁内执行下列逻辑:如果在abortEvtTab中未查询到目标线程的取消信号量,则判断目标线程是否已经终止,若已终止则返回失败,否则为目标线程创建取消信号量并将其添加到abortEvtTab中。
获得当前线程的取消信号量:function cthread_abort_evt();
cblock函数可用此函数获得当前线程的取消信号量,然后用WaitForMultipileObjects、select、poll、epoll等平台监听函数在等待操作完成的同时监听取消信号量,以检测取消请求。
平台支持TLS时,此函数通过TLS获得当前线程的取消信号量;平台不支持TLS时,此函数用当前线程的ID在abortEvtTab中查询得到当前线程的取消信号量。
当采用“取消信号量按需创建”的方式时,如果检测到当前线程的取消信号量不存在,则在cancelMngMutex锁内执行下列逻辑:在abortEvtTab中查找,若找到则将其复制到TLS中,否则创建取消信号量,将其添加到abortEvtTab并存储到TLS中。
设置当前线程取消信号量为无信号:functioncthread_abort_clear();
当需要复用cthread线程池中的线程时,在cthread开始执行耗时操作前,可调用此函数将当前线程的取消信号量设置为无信号。
此函数用cthread_abort_evt()获得当前线程的取消信号量,设置其状态为无信号。对Linux,可调用read()读取信号量的值,读取后信号量值会被置为0;在Windows中,可调用ResetEvent()设置信号量为无信号。
查询当前线程是否被请求取消:function cthread_aborted();
cblock函数在执行大计算等不能以阻塞方式等待操作完成的操作时,可间歇性调用此函数查询操作是否被请求取消。
此函数用cthread_abort_evt()获得当前线程的取消信号量,查询其状态以判断当前线程是否被请求取消。查询的一般方式是设置WaitForSigleObject、select、poll、epoll等监听函数的超时值为0。
将当前线程初始化为关联取消信号量的cthread:function cthread_init();
当App用平台API创建线程来执行cblock函数时,可以在线程开始执行时调用此函数将当前线程初始化为cthread。
此函数为当前线程创建取消信号量,设置其状态为无信号,并将其添加到abortEvtTab中,使当前线程关联取消信号量。对于支持TLS的平台,取消信号量可额外存储到TLS中。
将当前cthread去初始化为不关联取消信号量:function cthread_exit();
对于用cthread_init()初始线程为cthread的情形,在线程终止前,调用此函数去初始化。
此函数将当前线程的取消信号量从abortEvtTab中移除并销毁,使当前线程不再关联取消信号量。
创建cthread:function cthread_create();
App可通过此函数创建cthread,不需要手动调用cthread_init()将线程初始化为cthread。
仅当采用“取消信号量在线程启动时创建”的方式时,才需要实现此函数。对于“取消型号量按需创建”的方式,此函数可定义为平台线程创建函数的别名。
实现cthread_create()时,可以定义一个内部函数cthread_entry(),作为线程的入口函数。cthread_entry()执行步骤如下:调用cthread_init()将线程初始化为cthread;设置initSig为有信号;调用App的实际线程入口函数;调用cthread_exit()去初始化当前线程。
cthread_create()创建初始化完成通知信号量initSig,调用平台API,如pthread_create()、CreateThread()创建线程。线程入口函数设置为cthread_entry。
App调用cthread_create()会传入其线程入口地址func和入口参数param。cthread_create()动态分配一块内存cparam,将func、param及initSig等数据存储到cparam中。调用平台线程创建函数时,将cparam作为参数传入。cthread_entry()获得cparam,使用cparam.func、cparam.param来调用App提供的线程入口函数,设置cparam.initSig为有信号以通知cthread_create()执行线程新创建的cthread已完成初始化。
cthread_create()原型和语义一般与平台的线程创建API的保持一致,例如与POSIXpthread_create(),WinAPICreateThread()的保持一致。语义上的差异仅在于cthread_create()创建的是cthread,而平台API创建的是普通线程。
在一个更具体的实施例中,在Linux耗时操作API封装层实现时,用poll()来同时监听业务fd(文件描述符)和取消信号量fd。也可用epoll(),select()监听。
对于大多数LinixIOAPI,可在发出IO请求前先监听fd事件。例如对于read()、recv(),可先用poll()监听,监听到fd产生POLLIN事件时,再调用read()、recv()执行对fd的IO操作。这种情况,fd可以工作于异步模式,也可以工作于阻塞模式。
也有部分LinuxIOAPI,需要先发起异步IO请求,再监听fd事件。例如对于connect(),需要先发出异步connect()请求,再监听。poll()监听到fd产生POLLOUT事件,表示connect已经完成(成功或失败),此后调用getsockopt()获取其SO_ERROR选项值来判断connect是成功还是失败。这种情况,要求fd工作于异步模式。
对于需要先发出异步IO请求的封装函数,如connect_cs(),封装函数可以自动将fd设置为异步模式,并在函数返回时恢复为原有模式。这需要1~3次额外系统调用,导致一定的性能损失。实际实施时,可以做全局约定,约定所有fd在创建时,设置为异步模式。
大多数Linux API通过线程关联的errno返回错误码。封装函数检测到取消后,设置errno为取消错误码,返回指示错误的值(一般为-1)。取消错误码使用Linux的定义,ECANCELED。
除read()、write()、connect()等IO操作外,usleep()、poll()、epoll()、select()等非IO操作API也可视为耗时操作,可对其封装以支持取消检测。
下面以read()、connect()、usleep()、poll()的封装为例来演示封装Linux耗时操作API的一般方法。其中read()和connect()为IO耗时操作,usleep()为非IO耗时操作,poll()可视为IO相关耗时操作。
这些示例只展示封装的核心逻辑,具体实施时还需要处理各种错误、异常、signal等。
Linux read API的封装函数:function read_cs(fd, ...) ;
初始化poll监听列表fds,包括业务fd和当前线程的取消信号量fd。
其中,当前线程的取消型号量fd通过调用cthread_abort_evt()获得。
调用poll()监听列表中的fds,超时值设置为永久,
poll()会阻塞,直到业务fd可读或取消信号量fd有信号;
poll()返回后,根据监听结果处理,可以优先处理取消。
当监听到取消信号量fd可读(POLLIN事件)时,表示App对当前线程发出了取消请求。
不read取消信号量fd,设置errno为ECANCELED,返回-1。
当监听到业务fd可读(POLLIN事件)时,表示可以read业务fd而不会阻塞。
对业务fd发起read()调用,返回read()的返回值。
Linux connect API的封装函数:function connect_cs(fd, ...);
调用fcntl()判断fd是否工作于异步模式,若否,则调用fcntl将其设置为异步模式,并记录标志,在函数返回前,调用fcntl()将fd恢复为阻塞模式。
调用connect()发起异步连接请求。若操作成功,或失败且errno不是EINPROGRESS,表示connect()操作已经完成(成功或失败完成),则返回connect()的返回值。
初始化poll监听列表fds,包括业务fd和当前线程的取消信号量fd。
当前线程的取消型号量fd通过调用cthread_abort_evt()获得。
调用poll()监听fds列表,超时值设置为永久。
poll()会阻塞,直到业务fd可写或取消信号量fd有信号。
poll()返回后,根据监听结果处理,可以优先处理取消。
当监听到取消信号量fd可读(POLLIN事件)时,表示App对当前线程发出了取消请求。
不read取消信号量fd,设置errno为ECANCELED,返回-1。
当监听到业务fd可写(POLLOUT事件)时,调用getsockopt()获得SO_SOCKET的SO_ERROR属性值,其为错误码。若该错误码为0,表示connect成功,返回0;否则表示connect失败,设置errno为该错误码,返回-1。
Linux usleep API的封装函数:function usleep_cs(timeout);
初始化poll监听列表fds,只包括当前线程的取消信号量fd。
当前线程的取消信号量fd通过调用cthread_abort_evt()获得。
调用poll()监听fds列表,参数timeout的单位变换为毫秒后传给poll。
poll()会阻塞,直到超时,或取消信号量fd有信号。
poll()返回后,根据监听结果处理,可以优先处理取消。
当监听到取消信号量fd可读(POLLIN事件)时,表示App对当前线程发出了取消请求。
不read取消信号量fd,设置errno为ECANCELED,返回-1。
其它情形,返回poll()的返回值。返回值为0表示超时,返回值为-1表示检测到错误。
Linux poll API的封装函数:function poll_cs(fds, nfds, timeout);
分配新数组new_fds,其size为nfds+1,并将fds复制到new_fds中。
函数返回前,释放new_fds。
将当前线程的取消信号量fd存储为new_fds的末尾元素。
当前线程的取消信号量fd通过调用cthread_abort_evt()获得。
调用poll()监听new_fds列表,参数timeout透传给poll函数。
阻塞,直到超时,或fds有信号,或取消信号量fd有信号。
根据监听结果处理,可以优先处理取消。
当监听到取消信号量fd可读(POLLIN事件)时,表示App对当前线程发出了取消请求。
不read取消信号量fd,设置errno为ECANCELED,返回-1。
其它情形,返回poll()的返回值。
在一个更具体的实施例中,在Windows耗时操作API封装层实现时,用WindowsWaitForAPI来监听IO完成事件和取消事件。封装函数需要为IO操作创建一个Event对象ioEvent,存储到IOAPI需要的OVERLAPPED结构实例中。当IO操作完成时,Windows会设置ioEvent为有信号。封装函数通过WaitForAPI监听ioEvent状态变化,以检测操作完成。
用WaitForAPI来等待IO完成事件,需要使用Windows异步IO。可在创建File时,设置FILE_FLAG_OVERLAPPED标志,让对应文件或设备工作于异步模式(Overlapped模式)。
大多数WinAPI通过LastError返回错误码。WinAPI返回失败时,调用者通过GetLastError()获得错误码。封装函数返回错误码的方式与之保持一致。封装函数检测到取消后,通过SetLastError()设置取消错误码。取消错误码使用Windows的定义,ERROR_OPERATION_ABORTED。
除ReadFile()、WriteFile()等IO操作函数外,Sleep()、WaitFor()等非IO操作API也可视为耗时操作,也可对其封装以支持取消检测。
下面以ReadFile()、Sleep()、WaitForMultipleObject()的封装为例来演示封装Windows耗时操作API的一般方法。其中ReadFile()为IO耗时操作,Sleep()为非IO耗时操作,WaitForMultipleObjects()可视为IO相关耗时操作。
这些示例只展示封装的核心逻辑,具体实施时还需要处理各种错误、异常、WAIT_ABANDONED等。
ReadFile封装函数:function ReadFileCs(file, ...);
定义并初始化OVERLAPPED实例ol,创建Event实例ioEvent并存储到ol中。
在函数返回前,销毁ioEvent。
调用ReadFile()发起对file的异步read请求,ol引用通过参数传入。
若函数返回TRUE,或FALSE且错误码不是ERROR_IO_PENDING,表示ReadFile()操作已完成(成功或失败完成),则返回ReadFile()的返回值。
初始化WaitFor监听列表hnds,包括file和当前线程的取消信号量。
当前线程的取消型号量通过调用cthread_abort_evt()获得。
调用WaitForMultipleObjects()监听hnds列表,超时值设置为永久。
WaitFor会阻塞,直到ioEvent或取消信号量有信号。
WaitFor返回后,根据监听结果处理,可以优先处理取消。
当监听到取消信号量有信号时,表示App对当前线程发出了取消请求。
调用CancelIo()或CancelIoEx()对file发起IO取消请求。取消请求成功发出后,以等待方式(参数bWait置为TRUE)调用GetOverlappedResult()等到操作完成,并返回其返回值。
GetOverlappedResult()返回TRUE表示操作成功完成,返回FALSE且错误码为ERROR_OPERATION_ABORTED表示操作被成功取消,其它情形表示操作失败完成。
当监听到ioEvent有信号时,表示ReadFile操作已经完成。调用GetOverlappedResult()获取异步操作结果,并返回其返回值。以等待(参数bWait置为TRUE)或查询(参数bWait置为FALSE)方式调用GetOverlappedResult()均可。
Sleep封装函数,返回值类型从void变更为BOOL:function SleepCs(timeout);
调用WaitForSingleObject()监听取消信号量,参数timeout透传给WaitFor函数。
当前线程的取消型号量通过调用cthread_abort_evt()获得。
WaitFor会阻塞,直到超时,或取消信号量有信号。
WaitFor返回后,根据监听结果处理,可以优先处理取消。
当监听到取消信号量有信号时,表示App对当前线程发出了取消请求。
调用SetLastError()设置错误码为ERROR_OPERATION_ABORTED,返回FALSE。
当监听到超时时,表示WaitFor超时,返回TRUE表示sleepOK。
WaitForMultipleObject封装函数:function WaitForMultipleObjectsCs(hndNum, hnds, ...);
分配新数组newHnds,其size为hndNum+1。将hnds复制到newHnds中。
MAXIMUM_WAIT_OBJECTS是一个很小的值,可以定义newHnds为局部数组。
将当前线程的取消信号量存储为newHnds的末尾元素。
当前线程的取消信号量通过调用cthread_abort_evt()获得。
调用WaitForMultipleObjects()监听列表newHnds,参数timeout透传给WaitFor函数。
WaitFor会阻塞,直到超时,或取消信号量有信号。
WaitFor返回后,根据监听结果处理,可以优先处理取消。
当监听到取消信号量有信号时,表示App对当前线程发出了取消请求。
调用SetLastError()设置错误码为ERROR_OPERATION_ABORTED,返回WAIT_FAILED。
其他情形,返回WaitFor的返回值,保留WaitFor设置的LastError值。
示例的,在平台内核实施本耗时操作取消支持时,参见以下内容,以下示例基于Linux 4.9内核实施:
在task结构(struct task_struct)中增加属性abort_evt_fd,用来存储当前线程的取消信号量的fd(文件描述符)。取消信号量的filp(structfile指针)存储到task->files中,该filp在task->files的fd数组下标就是取消信号量的fd。
内核中建有task表,通过线程ID可查到线程的task实例,进而得到对应线程的取消信号量fd和filp。因此与在应用层实施不同,这里不需要额外map表来全局存储取消信号量。
按本例实施后,通过Linux API创建的线程都是cthread。因此不需要额外提供cthread_create API,Linux的线程创建API就是cthread创建API。
创建取消信号量:
本例采用取消信号量在创建线程时创建的方式。
创建线程时,最终会执行到do_clone()。修改该函数,在函数中创建取消信号量;调用get_unused_fd_flags()分配空闲fd作为取消信号量的fd;将取消信号量的filp添加到new_task(新建线程的task实例);将取消信号量的fd赋值给new_task->abort_evt_fd。
可参照sys_eventfd2()的实现方法创建取消信号量。sys_eventfd2()是为当前线程创建eventfd,而这里是为新建线程创建eventfd,因此这里需要将新建的eventfd的filp添加到new_task,而不是添加到current(当前线程的task实例)。取消信号量设置为异步模式。
do_clone()会确保完成必要处理后,新建线程才会有机会被调度执行,且取消信号量是由当前线程创建,而不是由新建线程创建,因而不存在应用层实施时涉及的同步等待问题。
销毁取消信号量
线程终止时,最终会执行到do_exit()。修改do_exit(),在函数中调用__close_fd()销毁当前线程的取消信号量。
获取当前线程的取消信号量:
current->abort_evt_fd即是当前线程的取消信号量的fd。
用current->abort_evt_fd在current->files中可定位到当前线程的取消信号量的filp。
获取指定线程的取消信号量:
调用find_task_by_vpid()在task表中查得指定线程的task实例。
task->abort_evt_fd即是目标线程的取消信号量的fd。
用task->abort_evt_fd在task->files中可定位到到目标线程的取消信号量的filp。
在内核的eventfd.c模块中增加一个接口函数以查询eventfd是否有信号:
function eventfd_test(eventfd_file);
入参eventfd_file为待测试eventfd的filp。
用eventfd_file调用eventfd_ctx_fileget()获得eventfd对象引用ctx。
用ctx->count的值来确定此eventfd是否有信号。
调用eventfd_ctx_put()释放引用ctx。
在内核的eventfd.c模块中增加一个接口函数以设置eventfd的状态为无信号:
function eventfd_clear(eventfd_file);
入参eventfd_file为待测试eventfd的filp。
用eventfd_file调用eventfd_ctx_fileget()获得eventfd对象引用ctx。
设置ctx->count的值为0。
调用eventfd_ctx_put()释放引用ctx。
在Linux内核实施时,需要提供下列系统调用接口:
cthread_cancel(cthreadId):发起对指定线程的取消请求。
cthread_abort_evt():获得当前线程的取消信号量fd。
cthread_abort_clear():设置当前线程的取消信号量为无信号。
cthread_aborted():查询当前线程是否被请求取消。
这些系统调用对应的内核函数实现方案如下。其命名按Linux惯例添加“sys_”前缀。
发起对指定线程的取消请求:functionsys_cthread_cancel(cthreadId):
用目标线程ID获得目标线程的取消信号量filp。
用该filp调用eventfd_ctx_fileget()获得其取消信号量对象引用ctx。
调用eventfd_signal()为ctx的状态值加1。
调用eventfd_ctx_put()释放取消信号量对象引用ctx。
获得当前线程的取消信号量fd:functionsys_cthread_abort_evt();
返回current->abort_evt_fd。
设置当前线程的取消信号量为无信号:function sys_cthread_abort_clear();
获得当前线程的取消信号量的filp。
用该filp调用eventfd_clear(),将取消信号量设置为无信号。
查询当前线程是否被请求取消:functionsys_cthread_aborted();
获得当前线程的取消信号量的filp。
用该filp调用eventfd_test(),根据其是否有信号来判断当前线程是否被请求取消。
在Linux内核实施时,不需要对App提供下列接口:
cancel_mng_init():初始化CancelMng。
cancel_mng_exit():去初始化CancelMng。
cthread_init():将当前线程初始化为关联取消信号量的cthread。
cthread_exit():将当前cthread去初始化为不关联取消信号量。
cthread_create():创建cthread。
示例的,在Linux 4.9内核实施本耗时操作取消支持时,将Linux耗时API改造为支持取消检测的cblock函数。改造处理在内核进行,修改的是系统调用的内核函数。例如对read() API的改造在内核函数sys_read()中进行。
Linux系统调用的内核函数,返回负整数来表示错误,其绝对值为错误码。系统调用的用户态函数会将错误码保存到线程相关errno。取消错误码使用Linux的定义,ECANCELED。
将Linux耗时操作API分为如下三类,分别采用不同的改造方案:
read、write、connect、recv等IO API;
当业务fd工作于异步模式时,不改造,按原有逻辑处理。
在对应内核函数中,用poll的内核函数来同时监听业务fd和当前线程的取消信号量fd。
对于需要先发起异步请求的API,先将业务fd修改为异步模式,再发起异步请求,然后再监听。函数返回前将业务fd恢复为阻塞模式。
nanosleep等sleepAPI;
在对应内核函数中,用poll的内核函数来监听取消信号量fd,设置对应超时值。
sleep、usleep等API是通过调用nanosleep()来实现的。
poll、epoll、select等监听API;
在对应内核函数中,将当前线程的取消信号量fd添加到监听列表来监听。监听使用对应内核函数的监听方法。
在改造Linux API时,一般会用到当前线程的取消型号量fd,这通过调用sys_cthread_abort_evt()来获得,或直接使用current->abort_evt_fd。
下面以read、connect、nanosleep、poll、select、epollAPI的改造为例,演示改造Linux耗时操作API的一般方法。这些示例只展示改造的核心逻辑,具体实施时还需要处理各种错误、异常、signal、加解锁等。
实现获取指定socket错误码的内核内部函数:function get_sock_err(fd);
调用sockfd_lookup_light(fd, ...)获得fd对应的sock(struct socket*)。
调用sock_err()获得sock的错误码。
改造read API的内核函数:function sys_read(fd, ...);
如果业务fd被设置为异步模式,则执行原有sys_read()代码,并返回。
初始化poll监听列表poll_list,包括业务fd和当前线程的取消信号量fd。
调用do_poll()监听poll_list,超时值设置为永久,
do_poll()会阻塞,直到业务fd可读或取消信号量fd有信号;
do_poll()返回后,根据监听结果处理,可以优先处理取消。
当监听到取消信号量fd可读(POLLIN事件)时,表示App对当前线程发出了取消请求。
返回-ECANCELED,指示当前操作被取消。
当监听到业务fd可读(POLLIN事件)时,表示可以读取业务fd而不会阻塞。
执行sys_read()原有处理代码。
改造connect API的内核函数:function sys_connect(fd, ...);
如果业务fd被设置为异步模式,则执行原有sys_connect()代码,并返回。
设置业务fd为异步模式。并在函数返回前,将其恢复为阻塞模式。
执行原有sys_connect()发起异步连接请求。若操作成功,或失败且错误码不是EINPROGRESS,表示connect操作已完成(成功或失败完成),则返回sys_connect()的返回值。
初始化poll监听列表poll_list,包括业务fd和当前线程的取消信号量fd。
调用do_poll()监听poll_list,超时值设置为永久。
do_poll()会阻塞,直到业务fd可写或取消信号量fd有信号。
do_poll()返回后,根据监听结果处理,可以优先处理取消。
当监听到取消信号量fd可读(POLLIN事件)时,表示App对当前线程发出了取消请求。
返回-ECANCELED,指示当前操作被取消。
当监听到业务fd可写(POLLOUT事件)时,调用get_sock_err()获得fd的错误码,并将其作为返回值返回。错误码为0,表示connect成功;否则表示connect失败。
改造nanousleep API的内核函数;function sys_nanosleep_cs();
初始化poll监听列表poll_list,只包括当前线程的取消信号量fd。
调用do_poll()监听fds列表,超时值根据入参设置。
do_poll()会阻塞,直到超时,或取消信号量fd有信号。
do_poll()返回后,根据监听结果处理。
当监听到取消信号量fd可读(POLLIN事件)时,表示App对当前线程发出了取消请求。
返回-ECANCELED,指示当前操作被取消。
其它情形,返回do_poll()的返回值。返回0表示超时,返回负值表示检测到错误。
改造poll API的内核函数:function do_sys_poll(fds, nfds, end_time);
此函数会将用户地址空间的fds复制到内核地址空间cfds。
将当前线程的取消信号量fd添加到cfds中。
当监听到取消信号量fd可读(POLLIN事件)时,表示App对当前线程发出了取消请求。
返回-ECANCELED,指示当前操作被取消。
其余按此函数原有逻辑处理。
对select API改造与对pollAPI的改造类似,在内核函数core_sys_select()中,将当前线程的取消信号量fd添加到内核空间的监听列表中,然后按正常流程监听和处理。当监听到取消信号量fd可读时,返回-ECANCELED,指示当前操作被取消。
对epollAPI的改造,可以在sys_epoll_create1()函数中,将当前线程的取消信号量fd添加到监听列表中。在sys_epoll_wait()的监听处理函数ep_poll()中,当监听到取消信号量fd可读,不将监听到的事件通过epoll_wait()的出参返回给App,而直接返回-ECANCELED,指示当前操作被取消。其余按原有逻辑处理。
在一个更具体的实施例中,在App中应用本取消方法时,在App中应用本取消方法和模块主要有以下两种场景:实现cblock函数和执行cblock函数;发起取消请求:
示例的,在App中实现cblock函数可分为如下几类,调用其他cblock函数,以实现更大粒度的cblock函数。用平台WaitFor、poll、epoll、select等监听API来查询或监听取消。大计算中间歇性查询当前cthread的取消信号量状态来检测取消。
在一个更具体的实施例中,实现cblock函数以实现更大粒度的cblock函数时,示例的,PING协议的主要过程为,客户端发起到服务器的TCP连接,通过TCP向服务器发送“PING”,服务器收到“PING”后,向客户端回送“PONG”。
实现客户端cblock函数ping_req。它以顺序逻辑调用平台封装层APIconnect_cs、write_cs、read_cs,以建立TCP连接,发送请求数据,接收响应数据。这些平台封装层API均为cblock函数,ping_req调用它们形成了更大粒度的cblock函数。
ping_req实现逻辑示意如下:调用socket创建socketfd。
调用connect_cs向连接服务器。
调用write_cs向服务器发送数据“PING”。
循环调用read_cs从服务器接收数据,直到接收到约定的字节数。
数据接收完成后,判断数据是否为“PONG”。若是,表示成功,否则表示失败。
调用close关闭fd。完成当次请求。
connect_cs、write_cs、read_cs都会检测取消。当检测到取消时,它们会返回-1,设置errno为ECANCELED。此时,ping_req终止操作,返回-1,并保留errno的错误码。
在一个更具体的实施例中,实现大计算cblock函数时,可以间歇性调用cthread_aborted,以查询方式检测取消。查询的间隔可设计为100ms、10ms、或1ms左右。根据间隔时间反推计算量,每当完成对应计算量后,调用cthread_aborted检测取消。
在一个更具体的实施例中,执行耗时操作及请求取消时,执行cblock函数ping_req,并向其发出取消请求。
App调用cthread_create创建cthread类型的worker线程。在worker线程入口函数中调用ping_req执行实际耗时操作。App在需要时调用cthread_cancel对该worker线程发出取消请求,并调用pthread_join等待其终止。ping_req检测到取消后会立刻返回,worker线程在ping_req返回后自然终止。调用cthread_cancel的可以是除该worker以外的其他任意线程。
在一个更具体的实施例中,在后台服务中应用时,本例为PING协议服务器端实现,PING服务器实现为后台服务。
App主函数调用cthread_create创建服务主线程,线程入口函数ping_svr_svc组织主服务代码。服务主线程监听PING客户端发起的TCP连接,对于每一个TCP连接,创建cthread类型的worker线程。worker线程入口函数ping_svr_sess组织会话处理代码,完成一次与客户端的PING-PONG交互。worker线程完成操作后,向服务主线程发送完成通知事件。服务主线程检测到完成通知事件后,用pthread_join等待对应的worker线程结束。
ping_svr_sess与ping_req类似,执行的是典型的IO耗时操作。ping_svr_sess实现为cblock函数。它首先循环调用read_cs接收PING客户端发送的请求数据,直到收到约定的字节数;然后判断请求数据是否为“PING”,若是,则调用write_cs发送响应数据“PONG”。write_cs、read_cs都会检测取消。当检测到取消时,它们会返回-1,设置errno为ECANCELED。此时,ping_svr_sess返回,worker线程自然终止。无论操作是否成功,无论操作失败的原因是否因为检测到取消,ping_svr_sess返回前均向服务主线程发送完成通知事件。
worker线程通过packet类型的pipe向服务主线程发送完成通知事件,事件体为worker线程ID。pipe由ping_svr_svc创建,并通过参数传递给worker线程的入口函数ping_svr_sess。
在服务执行期间的任意时刻,会有一个服务主线程,及任意多个worker线程。worker线程由服务主线程创建。服务主线程除了监听TCP连接事件和worker完成通知事件外,还同时监听取消事件。监听到取消事件后,服务主线程向当前活动的所有worker线程发出取消请求,并调用pthread_join等待它们终止,最后自然终止服务主线程。至此,所有worker线程和服务主线程均优雅终止。
App主函数先创建服务主线程来执行ping_svr_svc,然后监听SIGINT、SIGQUIT、SIGTERM信号(LinuxSignal)。用户键入CTRL+C或执行kill命令会发出对应信号。App主函数监听到对应信号后,用cthread_cancel向服务主线程发出取消请求,并用pthread_join等待其终止。
以上所述的具体实施方式,对本发明的目的、技术方案和有益效果进行了进一步详细说明,所应理解的是,以上所述仅为本发明的具体实施方式而已,并不用于限定本发明的保护范围,凡在本发明的精神和原则之内,所做的任何修改、等同替换、改进等,均应包含在本发明的保护范围之内。
Claims (10)
1.一种耗时操作取消及阻塞异步转换的方法,其特征在于,包括:
创建耗时操作线程,并将所述耗时操作线程异步运行于后台;
为所述耗时操作线程建立二状态信号量,所述二状态信号量的状态包括有信号和无信号;
当任意线程对所述耗时操作进行取消时,将所述二状态信号量的状态修改为有信号;
所述耗时操作线程监听或查询到所述二状态信号量的状态为有信号时,取消所述耗时操作。
2.根据权利要求1所述的一种耗时操作取消及阻塞异步转换的方法,其特征在于,创建耗时操作线程,并将所述耗时操作线程异步运行于后台包括:
创建耗时操作线程时,将对阻塞函数的一次调用的信息打包进函数对象中;
通过第一异步支持模块创建耗时操作线程,所述耗时操作线程调用并执行所述函数对象;
通过第二异步支持模块在监听耗时操作线程完成操作的同时监听并分发UI消息,以响应UI操作;
当所述耗时操作线程调用执行所述函数对象,并待其返回后发出完成通知;
使用所述函数对象中记录的完成通知方式和附加信息发出完成通知;所述完成通知方式和所述附加信息由App在发起异步请求时指定。
3.根据权利要求1所述的一种耗时操作取消及阻塞异步转换的方法,其特征在于,多个所述耗时操作线程对应的二状态信号量被存储于全局表中;
任意线程通过所述全局表获取所述耗时操作线程对应的二状态信号量。
4.根据权利要求1所述的一种耗时操作取消及阻塞异步转换的方法,其特征在于,每一个耗时操作线程对应至少一个阻塞函数;
一个阻塞函数可以调用任意数目,任意层次的子阻塞函数,形成大粒度阻塞函数;
在所述大粒度阻塞函数的任意子阻塞函数中通过查询或监听获取对应所述耗时操作线程的二状态信号量为有信号,或通过子阻塞函数返回的错误码检测到操作被取消时,所述子阻塞函数通过错误码向外层函数指示操作被取消,直至最外层阻塞函数。
5.根据权利要求1所述的一种耗时操作取消及阻塞异步转换的方法,其特征在于,还包括:
在创建耗时操作线程之前创建取消管理模块;所述取消管理模块被配置为对所述二状态信号量进行管理和支持线程获取所述二状态信号量;
当任意线程对所述耗时操作进行取消时,所述取消管理模块将所述耗时操作线程对应的二状态信号量修改为有信号;
所述取消管理模块支持所述耗时操作线程获取当前线程的二状态信号量,并根据当前线程的二状态信号量状态判断操作是否被请求取消。
6.一种耗时操作取消及阻塞异步转换的系统,其特征在于,包括:
创建单元,被配置为创建耗时操作线程,并将所述耗时操作线程异步运行于后台;
信号量单元,被配置为为所述耗时操作线程建立二状态信号量,所述二状态信号量的状态包括有信号和无信号;
修改单元,被配置为当任意线程对所述耗时操作进行取消时,将所述二状态信号量的状态修改为有信号;
取消单元,所述耗时操作线程监听或查询到所述二状态信号量的状态为有信号时,取消所述耗时操作。
7.根据权利要求6所述的一种耗时操作取消及阻塞异步转换的系统,其特征在于,创建耗时操作线程时,所述创建单元将对阻塞函数的一次调用的信息打包进函数对象中;
通过第一异步支持模块创建耗时操作线程,所述耗时操作线程调用并执行所述函数对象;
通过第二异步支持模块在监听耗时操作线程完成操作的同时监听并分发UI消息,以响应UI操作;
当所述耗时操作线程调用执行所述函数对象,并待其返回后发出完成通知;
使用所述函数对象中记录的完成通知方式和附加信息发出完成通知;所述完成通知方式和所述附加信息由App在发起异步请求时指定。
8.根据权利要求6所述的一种耗时操作取消及阻塞异步转换的系统,其特征在于,多个所述耗时操作线程对应的二状态信号量被存储于全局表中;
任意线程通过所述全局表获取所述耗时操作线程对应的二状态信号量。
9.根据权利要求6所述的一种耗时操作取消及阻塞异步转换的系统,其特征在于,每一个耗时操作线程对应至少一个阻塞函数;
一个阻塞函数可以调用任意数目,任意层次的子阻塞函数,形成大粒度阻塞函数;
在所述大粒度阻塞函数的任意子阻塞函数中通过查询或监听获取对应所述耗时操作线程的二状态信号量为有信号,或通过子阻塞函数返回的错误码检测到操作被取消时,所述子阻塞函数通过错误码向外层函数指示操作被取消,直至最外层阻塞函数。
10.根据权利要求6所述的一种耗时操作取消及阻塞异步转换的系统,其特征在于,还包括:
取消管理模块,被配置为对所述二状态信号量进行管理和支持线程获取所述二状态信号量;
当任意线程对所述耗时操作进行取消时,所述取消管理模块将所述耗时操作线程对应的二状态信号量修改为有信号;
所述取消管理模块支持所述耗时操作线程获取当前线程的二状态信号量,并根据当前线程的二状态信号量状态判断操作是否被请求取消。
Priority Applications (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN202110911090.XA CN113360302B (zh) | 2021-08-10 | 2021-08-10 | 一种耗时操作取消及阻塞异步转换的方法及系统 |
Applications Claiming Priority (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN202110911090.XA CN113360302B (zh) | 2021-08-10 | 2021-08-10 | 一种耗时操作取消及阻塞异步转换的方法及系统 |
Publications (2)
Publication Number | Publication Date |
---|---|
CN113360302A true CN113360302A (zh) | 2021-09-07 |
CN113360302B CN113360302B (zh) | 2021-10-29 |
Family
ID=77540852
Family Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN202110911090.XA Active CN113360302B (zh) | 2021-08-10 | 2021-08-10 | 一种耗时操作取消及阻塞异步转换的方法及系统 |
Country Status (1)
Country | Link |
---|---|
CN (1) | CN113360302B (zh) |
Citations (7)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN104063276A (zh) * | 2013-03-18 | 2014-09-24 | 腾讯科技(深圳)有限公司 | 一种窗口任务处理的方法及装置 |
CN104601523A (zh) * | 2013-10-31 | 2015-05-06 | 腾讯科技(深圳)有限公司 | 一种传输数据的方法及装置 |
CN106021399A (zh) * | 2016-05-12 | 2016-10-12 | 网易(杭州)网络有限公司 | 查询请求消息的处理方法及装置 |
CN107436817A (zh) * | 2017-06-30 | 2017-12-05 | 武汉斗鱼网络科技有限公司 | 一种以同步方式进行远程过程调用的方法及装置 |
CN107562540A (zh) * | 2017-09-05 | 2018-01-09 | 武汉斗鱼网络科技有限公司 | 向ui线程投递回调函数的方法、装置及客户端 |
US10691501B1 (en) * | 2016-10-25 | 2020-06-23 | Amazon Technologies, Inc. | Command invocations for target computing resources |
CN111435314A (zh) * | 2019-01-11 | 2020-07-21 | 武汉瓯越网视有限公司 | 一种不阻塞线程等待异步消息的方法、系统、服务器及存储介质 |
-
2021
- 2021-08-10 CN CN202110911090.XA patent/CN113360302B/zh active Active
Patent Citations (7)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN104063276A (zh) * | 2013-03-18 | 2014-09-24 | 腾讯科技(深圳)有限公司 | 一种窗口任务处理的方法及装置 |
CN104601523A (zh) * | 2013-10-31 | 2015-05-06 | 腾讯科技(深圳)有限公司 | 一种传输数据的方法及装置 |
CN106021399A (zh) * | 2016-05-12 | 2016-10-12 | 网易(杭州)网络有限公司 | 查询请求消息的处理方法及装置 |
US10691501B1 (en) * | 2016-10-25 | 2020-06-23 | Amazon Technologies, Inc. | Command invocations for target computing resources |
CN107436817A (zh) * | 2017-06-30 | 2017-12-05 | 武汉斗鱼网络科技有限公司 | 一种以同步方式进行远程过程调用的方法及装置 |
CN107562540A (zh) * | 2017-09-05 | 2018-01-09 | 武汉斗鱼网络科技有限公司 | 向ui线程投递回调函数的方法、装置及客户端 |
CN111435314A (zh) * | 2019-01-11 | 2020-07-21 | 武汉瓯越网视有限公司 | 一种不阻塞线程等待异步消息的方法、系统、服务器及存储介质 |
Non-Patent Citations (2)
Title |
---|
YUNGANG JIA等: "Automatic realization of serial Communication", 《2011 INTERNATIONAL CONFERENCE ON ELECTRICAL AND CONTROL ENGINEERING》 * |
张云临: "通过Event事件正确结束线程", 《HTTPS://WWW.CNBLOGS.COM/ZHANGYUNLIN/P/6168011.HTML》 * |
Also Published As
Publication number | Publication date |
---|---|
CN113360302B (zh) | 2021-10-29 |
Similar Documents
Publication | Publication Date | Title |
---|---|---|
US8706881B2 (en) | Automatic registration of enterprise resources in a dynamic module system services registry | |
US6173442B1 (en) | Busy-wait-free synchronization | |
US8661410B2 (en) | Managed enterprise software components as dynamic services | |
US7904886B2 (en) | Method for executing an application in a virtual container forming a virtualized environment session | |
AU638138B2 (en) | Methods and apparatus for implementing data bases to provide object-oriented invocation of applications | |
US8856734B2 (en) | Type-safe dependency injection of services into enterprise components | |
US6044224A (en) | Mechanism for dynamically associating a service dependent representation with objects at run time | |
US6006235A (en) | Method and apparatus for invoking a stored procedure or a user defined interpreted language function in a database management system | |
US9760583B2 (en) | Method for native program to inherit same transaction context when invoked by primary program running in separate environment | |
EP0924607A2 (en) | Method and apparatus for fast local CORBA object references | |
JPH1049380A (ja) | スペース効率の良いオブジェクト・ロッキング・システム及び方法 | |
US8060788B2 (en) | Real-time signal handling in guest and host operating systems | |
CN111857993B (zh) | 一种内核态调用用户态函数的方法 | |
US11422777B2 (en) | System and methods with reduced complexity in the integration of exposed information models with applications | |
CA2386658A1 (en) | System of reusable software parts for implementing concurrency and hardware access, and methods of use | |
JP2004536382A (ja) | 置換可能なサービス品質機能のあるネットワーク通信チャネルコンポーネントを選択するために、置換可能なコンポーネントを用いるシステム、方法及び製造物 | |
JP2000215070A (ja) | ロバスト且つ回復可能なプロセス間ロック | |
US6205491B1 (en) | Method and apparatus for deferred throwing of exceptions in C++ | |
EP2847670A1 (en) | System and method for supporting a deferred reference to an object in an objected-oriented programming language environment | |
US8429621B2 (en) | Component lock tracing by associating component type parameters with particular lock instances | |
JPH11224203A (ja) | リモートオブジェクトコール方法、コンピュータ読み取り可能な記憶媒体、リモートオブジェクトコール処理方法、及び分散型コンピュータネットワークシステム | |
CN113360302B (zh) | 一种耗时操作取消及阻塞异步转换的方法及系统 | |
US7512953B1 (en) | System and method for smart proxy creation and management within a distributed object-oriented architecture | |
US11861416B2 (en) | Critical section speedup using help-enabled locks | |
CN114610381A (zh) | 一种方法服务的调用方法、装置、设备及存储介质 |
Legal Events
Date | Code | Title | Description |
---|---|---|---|
PB01 | Publication | ||
PB01 | Publication | ||
SE01 | Entry into force of request for substantive examination | ||
SE01 | Entry into force of request for substantive examination | ||
GR01 | Patent grant | ||
GR01 | Patent grant |