launch once 与 dispatch once

本文详细解析了launchonce和dispatch_once在Engine对象生命周期内调用次数的差异,指出dispatch_once虽然在App生命周期内只调用一次,但其内部实现可能不符合预期。同时,讨论了使用self作为onceToken的不可行性,并分析了dispatch_once内部的线程安全设计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

昨天发了个 launch once 的 code snippet 


陆续有朋友和我讨论,今天详细解释下。

launch once 这段代码实现了在一个 Engine 对象生命周期内只能调用一次 launch 方法:




而我们常用的 dispatch once 由于其使用了一个 static 变量作为 onceToken,所以会在 App 生命周期内只调用一次:




所以是这样的效果:




并不是我们所期望的。

有朋友考虑这个写法是否线程安全,其实当使用一个标记 property 的传统写法来干同样的事时,真的有考虑过线程安全么?不过也去查看了下 runtime 源码,对 association 的访问和操作都是通过内部一个 AssociationsManager C++ 类实现,而在它的实例的生命周期内,存在一把 spinlock 来保证线程安全:




因此反而还挺线程安全。昨天还讨论了有没有可能利用 dispatch_once 加上一个非 static 变量的 onceToken 来实现这个需求,比如用 self 当 onceToken。后经研究发现并不能做到,因为 dispatch_once 的实现对 onceToken 有比较苛刻的限制条件:

  • onceToken 初始值必须是 0

  • onceToken 必须是 long 类型

  • 在生命周期内 onceToken 的地址不能修改,且值不能被乱改


任何不满足都会 BAD_ACCESS,所以用 self 当 onceToken 是不可行的,只可能用一个成员变量来充当,但是这已经违背了“不添加成员变量”的初衷,晚上失眠时想了好久怎么能找到个酷炫的 onceToken 来解决这个难题,结果失眠的时间更久了...


有关 dispatch_once 内部的精巧设计,可以拜读梦维的系列博文,讲的非常之深入:


http://www.dreamingwish.com/article/gcd-guide-dispatch-once-1.html


最后,还有吐槽为啥那段代码就不多打几个回车的,其实只是为了臭美用两行代码就能搞定 - -,平时用该咋写咋写啊

<>:55: SyntaxWarning: invalid escape sequence '\C' <>:55: SyntaxWarning: invalid escape sequence '\C' C:\Users\qjlkw\AppData\Local\Temp\ipykernel_24372\1918439027.py:55: SyntaxWarning: invalid escape sequence '\C' file_path = "C:\附件\附件\C题附件.xlsx" A module that was compiled using NumPy 1.x cannot be run in NumPy 2.2.4 as it may crash. To support both 1.x and 2.x versions of NumPy, modules must be compiled with NumPy 2.0. Some module may need to rebuild instead e.g. with 'pybind11>=2.12'. If you are a user of the module, the easiest solution will be to downgrade to 'numpy<2' or try to upgrade the affected module. We expect that some modules will need time to support NumPy 2. Traceback (most recent call last): File "<frozen runpy>", line 198, in _run_module_as_main File "<frozen runpy>", line 88, in _run_code File "c:\ProgramData\anaconda3\Lib\site-packages\ipykernel_launcher.py", line 17, in <module> app.launch_new_instance() File "c:\ProgramData\anaconda3\Lib\site-packages\traitlets\config\application.py", line 1075, in launch_instance app.start() File "c:\ProgramData\anaconda3\Lib\site-packages\ipykernel\kernelapp.py", line 701, in start self.io_loop.start() File "c:\ProgramData\anaconda3\Lib\site-packages\tornado\platform\asyncio.py", line 205, in start self.asyncio_loop.run_forever() File "c:\ProgramData\anaconda3\Lib\asyncio\windows_events.py", line 322, in run_forever super().run_forever() File "c:\ProgramData\anaconda3\Lib\asyncio\base_events.py", line 641, in run_forever self._run_once() File "c:\ProgramData\anaconda3\Lib\asyncio\base_events.py", line 1986, in _run_once handle._run() File "c:\ProgramData\anaconda3\Lib\asyncio\events.py", line 88, in _run self._context.run(self._callback, *self._args) File "c:\ProgramData\anaconda3\Lib\site-packages\ipykernel\kernelbase.py", line 534, in dispatch_queue await self.process_one() File "c:\ProgramData\anaconda3\Lib\site-packages\ipykernel\kernelbase.py
03-27
资源下载链接为: https://pan.quark.cn/s/9e7ef05254f8 行列式是线性代数的核心概念,在求解线性方程组、分析矩阵特性以及几何计算中都极为关键。本教程将讲解如何用C++实现行列式的计算,重点在于如何输出分数形式的结果。 行列式定义如下:对于n阶方阵A=(a_ij),其行列式由主对角线元素的乘积,按行或列的奇偶性赋予正负号后求和得到,记作det(A)。例如,2×2矩阵的行列式为det(A)=a11×a22-a12×a21,而更高阶矩阵的行列式可通过Laplace展开或Sarrus规则递归计算。 在C++中实现行列式计算时,首先需定义矩阵类或结构体,用二维数组存储矩阵元素,并实现初始化、加法、乘法、转置等操作。为支持分数形式输出,需引入分数类,包含分子和分母两个整数,并提供整数、浮点数的转换以及加、减、乘、除等运算。C++中可借助std::pair表示分数,或自定义结构体并重载运算符。 计算行列式的函数实现上,3×3及以下矩阵可直接按定义计算,更大矩阵可采用Laplace展开或高斯 - 约旦消元法。Laplace展开是沿某行或列展开,将矩阵分解为多个小矩阵的行列式乘积,再递归计算。在处理分数输出时,需注意避免无限循环和除零错误,如在分数运算前先约简,确保分子分母互质,且所有计算基于整数进行,最后再转为浮点数,以避免浮点数误差。 为提升代码可读性和可维护性,建议采用面向对象编程,将矩阵类和分数类封装,每个类有明确功能和接口,便于后续扩展如矩阵求逆、计算特征值等功能。 总结C++实现行列式计算的关键步骤:一是定义矩阵类和分数类;二是实现矩阵基本操作;三是设计行列式计算函数;四是用分数类处理精确计算;五是编写测试用例验证程序正确性。通过这些步骤,可构建一个高效准确的行列式计算程序,支持分数形式计算,为C++编程和线性代数应用奠定基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值