我在网上发现了几个地方,这些地方指出,每当进入中断例程时,都必须调用CLREX,这是我不理解的。 CLREX状态的文档(添加了编号以方便参考):
(1)清除执行处理器的本地记录,该记录是某个地址已请求独占访问。
(2)使用
CLREX
指令将紧密耦合的互斥访问监视器返回其开放访问状态。这样就消除了将虚拟存储存储到内存的需求。(3)由
CLREX
是否也清除执行处理器的全局记录,即地址已请求独占访问。
我在这里什么都不懂。
我的印象是,按照example in the docs的方式写东西足以保证原子性:
MOV r1, #0x1 ; load the ‘lock taken’ value
try: <---\
LDREX r0, [LockAddr] ; load the lock value |
CMP r0, #0 ; is the lock free? |
STREXEQ r0, r1, [LockAddr] ; try and claim the lock |
CMPEQ r0, #0 ; did this succeed? |
BNE try ; no - try again ------------/
.... ; yes - we have the lock
为什么需要清除“本地记录”?我认为LDREX
/ STREX
足以保证从多个中断中原子访问地址?即GCC for ARM使用LDREX
/ STREX
编译了所有C11原子函数,但我看不到CLREX
在任何地方都被调用。
第二段所指的是“虚拟商店的要求”?
global 记录和 local 记录有什么区别?多核方案是否需要全球记录?
答案 0 :(得分:4)
分别回答(和解释)您的三个问题:
1。为什么要清除访问记录?
当强制执行严格的代码嵌套时,例如在处理中断时,通常不需要CLREX
。但是,在某些情况下它很重要。想象一下,您正在为抢先式操作系统内核编写上下文切换,该上下文切换可以异步挂起正在运行的任务并继续执行另一个任务。现在考虑以下病理状况,涉及两个相同优先级的任务(A和B),这些任务使用LDREX
和STREX
来操纵同一共享资源:
Task A Task B
...
LDREX
-------------------- context switch
LDREX
STREX (succeeds)
...
LDREX
-------------------- context switch
STREX (succeeds, and should not)
...
因此,上下文切换必须发出CLREX
来避免这种情况。
2。避免了什么“虚拟商店要求”?
如果没有CLREX
指令,则有必要使用STREX
放弃互斥访问标志,该标志涉及内存事务,因此比需要的速度慢如果您要做的就是清除标志。
3。是多核方案的“全球记录”吗?
是的,如果您使用的是单核计算机,则只有一条记录,因为只有一个CPU。
答案 1 :(得分:1)
实际上,M7上的异常/中断不需要CLREX
,它似乎仅出于兼容性原因而被包括在内。来自documenation (Version c):
CLREX支持与其他具有以下功能的ARM Cortex处理器的兼容性: 发生异常时强制存储独占失败 在加载独占指令和匹配存储独占之间 同步操作中的指令。在Cortex-M处理器中, 本地独占访问监视器会自动清除 异常边界,因此使用CLREX的异常处理程序是可选的。
因此,由于Cortex-M处理器在异常/中断进入/退出时清除了本地独占访问标志,因此这将CLREX
的大多数(全部?)用例否定。
关于第三个问题,正如其他人提到的那样,您认为在多核方案中使用全局记录是正确的。根据实现定义的对本地/全局标志的影响,多核处理器上的CLREX
仍可能存在用例。
我可以理解为什么对此感到困惑,因为M7文档的初始版本不包含这些语句(更不用说ARM网站上更通用的文档的其他各种版本)。即使是现在,我什至无法链接到最新版本。默认情况下,该页面显示“版本a”,您必须通过下拉框手动更改版本(希望以后会更改)。
为回应评论,为此提供了附加文档link。这是手册的一部分,描述了特定说明文档之外的这些说明的用法(并且自第一次修订以来就存在):
在以下情况下,处理器将删除其独占访问标签:
它执行CLREX指令。
无论写入是否成功,它都会执行STREX指令。
发生异常。这意味着处理器可以解决不同线程之间的信号量冲突。
在多处理器实现中:
执行CLREX指令仅删除处理器的本地独占访问标签。
执行STREX指令或异常会删除处理器的本地独占访问标签。
对共享内存区域执行STREX指令还可以删除处理器中的全局独占访问标签。 系统。