关于__weak 和 __strong配和使用的原因

本文探讨了在Objective-C中使用__weak弱引用与__strong强引用的区别,特别是在block内外的作用。通过示例展示了弱引用如何帮助优化内存管理。

 

之前,看到关于blcok外使用__weak弱化对象,blcok内再用 __strong 强引用的原因:

保证对象在blcok中不会被提前释放,当blcok执行完之后,自动释放该对象。

今天看了一下__weak修饰的对象,在被使用的时候,每次使用都会被注册到autoreleasepool中,例如:

{

id __weak o = obj;

NSLog(@"%@",obj);

NSLog(@"%@",obj);

NSLog(@"%@",obj);

NSLog(@"%@",obj);

}

这样,o 所赋值的对象被注册到自动释放池中5次。

而强引用之后,id temp = o,再次打印的话,则仅仅注册了1次。所以,这对于内存优化也有一些的帮助吧。

转载于:https://www.cnblogs.com/rendaochoucheng/p/7248684.html

<think>我们正在讨论C++原子操作中的compare_exchange_strongcompare_exchange_weak的区别。 这两个函数都是用于原子比较并交换(CAS)操作,但行为上存在细微差别,尤其是在某些平台上的表现。 根据引用[1]引用[2]: - 这些操作(exchangecompare_exchange)封装了平台上最高性能的实现。 - compare_exchange(CAS)是无锁编程中常用的操作。 具体区别如下: 1. 函数签名: bool compare_exchange_weak( T& expected, T desired, std::memory_order success, std::memory_order failure ) noexcept; bool compare_exchange_strong( T& expected, T desired, std::memory_order success, std::memory_order failure ) noexcept; 2. 行为差异: - compare_exchange_weak:即使当前值与expected相等,也可能失败(返回false),这种情况称为虚假失败(spurious failure)。这通常发生在某些硬件架构上(如LL/SC架构),在这些架构上,即使没有其他线程修改,也可能由于各种原因(如缓存一致性操作、中断等)导致操作失败。因此,它通常用在循环中,例如: while (!atomic_val.compare_exchange_weak(expected, desired)) { ... } - compare_exchange_strong:保证当当前值与expected相等时,交换一定会成功(除非被其他线程干扰)。因此,它不会出现虚假失败。但是,它的代价可能是更高的性能开销(在某些平台上)。 3. 性能考虑: - 在循环中,使用weak版本可能更高效,因为某些平台实现weak版本可以避免一些开销,但需要处理虚假失败(即循环可能多执行几次)。 - 而strong版本在循环中可能更简单,因为不需要处理虚假失败,但每次尝试可能更重。 4. 使用场景: - 当在循环中执行CAS操作时(这是常见模式),通常使用weak版本,因为即使出现虚假失败,循环会再次尝试,而且weak版本可能更快。 - 当需要严格的一次性条件判断(不在循环中)时,使用strong版本,因为如果它返回false,那么一定是值不匹,而不是虚假失败。 5. 例子: 考虑一个无锁栈的pop操作(伪代码): while (true) { Node* old_top = top.load(); if (old_top == nullptr) return nullptr; Node* new_top = old_top->next; if (top.compare_exchange_weak(old_top, new_top)) return old_top; // 否则,循环重试(可能是其他线程修改了top,也可能是weak的虚假失败) } 这里使用weak版本是合适的,因为即使出现虚假失败,我们也会重试。 6. 注意:在x86架构上,由于硬件支持强大的CAS操作,weakstrong的实现通常是一样的,不会出现虚假失败。但在ARM、PowerPC等使用LL/SC(加载链接/条件存储)的架构上,weakstrong的行为差异就体现出来了。 7. 结论: - 在循环中,优先使用compare_exchange_weak,因为它可能更高效。 - 如果不在循环中,或者需要避免虚假失败带来的额外循环,则使用compare_exchange_strong。 8. 引用标准: C++标准规定,weak版本允许虚假失败,而strong版本则不允许。 根据以上分析,我们可以总结如下: | 特性 | compare_exchange_weak | compare_exchange_strong | |----------------------|-----------------------------|-----------------------------| | 虚假失败 | 可能发生 | 不会发生 | | 性能 | 通常更低开销(某些平台) | 可能更高开销(某些平台) | | 使用场景 | 循环中 | 非循环或需要确定性的情况 | 最后,注意两个函数都需要我们传递一个expected的引用,这个值在操作失败时会被更新为原子变量的当前值。 参考引用[1]中提到的,这些函数封装了平台上的最高性能实现,因此我们在不同平台上使用它们都能获得最佳性能。 下面是一个简单的代码示例,展示了两者的使用: ```cpp #include <atomic> #include <iostream> int main() { std::atomic<int> a(10); int expected = 10; // 使用compare_exchange_weak bool success = a.compare_exchange_weak(expected, 20); std::cout << "weak: " << success << ", a=" << a << ", expected=" << expected << '\n'; // 重置 a = 10; expected = 10; // 使用compare_exchange_strong success = a.compare_exchange_strong(expected, 30); std::cout << "strong: " << success << ", a=" << a << ", expected=" << expected << '\n'; // 尝试一个会失败的例子 expected = 15; // 当前a是30,所以不匹 success = a.compare_exchange_weak(expected, 40); // 此时,expected被更新为当前a的值(30) std::cout << "weak (fail): " << success << ", expected=" << expected << '\n'; } ``` 输出可能是: weak: 1, a=20, expected=10 strong: 1, a=30, expected=10 weak (fail): 0, expected=30 注意:在weak操作中,即使我们期望的值是10,并且a确实是10,但weak操作也可能因为虚假失败而返回0(但在本例中,由于没有竞争,weak操作应该成功)。 在实际多线程环境中,使用weak版本时,必须考虑在失败时重试(通常通过循环)。 因此,在编写无锁数据结构时,通常使用weak版本在循环中重试,直到成功或满足其他条件。 §§相关问题§§ 1. 在哪些硬件平台上compare_exchange_weakcompare_exchange_strong的行为差异最为明显? 2. 如何避免CAS操作中的ABA问题? 3. 无锁编程中,除了CAS,还有哪些常用的原子操作?</think>### C++ `compare_exchange_strong` vs `compare_exchange_weak` 的区别 在 C++ 原子操作中,`compare_exchange_strong` `compare_exchange_weak` 都是**原子比较并交换(Compare-And-Swap, CAS)** 操作的核心函数,用于实现无锁编程。它们的核心区别在于**对操作失败的处理方式**,这直接影响性能使用场景。以下是详细分析: --- #### 1. **函数签名与基本行为** 两种方法的签名相同: ```cpp bool compare_exchange_strong(T& expected, T desired, ...); bool compare_exchange_weak(T& expected, T desired, ...); ``` - **参数**: - `expected`:期望的原子变量当前值(若匹则更新)。 - `desired`:需要设置的新值。 - **返回值**: - `true`:交换成功(原子变量的值等于 `expected` 并被设为 `desired`)。 - `false`:交换失败(原子变量的值不等于 `expected`,此时 `expected` 被更新为实际值)。 --- #### 2. **核心区别:失败场景** | 特性 | `compare_exchange_strong` | `compare_exchange_weak` | |-------------------------------|-----------------------------------------|-----------------------------------------| | **失败原因** | 仅因值不匹失败(无虚假失败) | 可能因值不匹**或硬件原因**失败 | | **虚假失败(Spurious Failure)** | ❌ 永远不会发生 | ✔️ 可能发生(即使值匹也可能失败) | | **性能开销** | 较高(需严格保证原子性) | 较低(允许宽松的硬件优化) | | **典型使用场景** | 非循环的确定性操作 | 循环重试结构(如自旋锁) | > 💡 **虚假失败**:某些硬件架构(如 ARM/PowerPC 的 LL/SC 指令)因中断、缓存一致性等问题,即使值匹也可能报告失败。 --- #### 3. **使用场景与代码示例** ##### (1) **`compare_exchange_weak`:循环重试场景** 适用于需多次重试的循环结构(如自旋锁),容忍虚假失败: ```cpp std::atomic<int> val(0); void increment() { int expected = val.load(); while (!val.compare_exchange_weak(expected, expected + 1)) { // 失败时:expected 已更新为实际值,继续重试 } } ``` - **优势**:在循环中性能更高(允许硬件优化)[^1][^2]。 ##### (2) **`compare_exchange_strong`:确定性操作** 适用于需要一次成功或明确失败的场景: ```cpp bool try_lock(std::atomic_flag& lock) { bool expected = false; // 仅尝试一次,无循环 return lock.compare_exchange_strong(expected, true); } ``` - **优势**:结果严格可靠,避免重试逻辑[^1]。 --- #### 4. **底层硬件实现的差异** - **x86 架构**:两者通常无性能差异(均基于 `CMPXCHG` 指令实现)。 - **ARM/PowerPC 架构**: - `weak` 使用 **Load-Linked/Store-Conditional (LL/SC)** 指令,可能因中断或缓存失效导致虚假失败。 - `strong` 通过重试 LL/SC 保证严格成功,开销更大[^1][^2]。 --- #### 5. **如何选择?** | **场景** | **推荐方法** | **原因** | |-----------------------------------|---------------------------|----------------------------------------| | 循环结构(如自旋锁、无锁队列) | `compare_exchange_weak` | 容忍虚假失败,性能更高 | | 单次尝试操作(如条件触发) | `compare_exchange_strong` | 避免意外失败,逻辑更简单 | | 需要严格保证原子性的关键操作 | `compare_exchange_strong` | 结果绝对可靠 | > ⚠️ **注意**:使用 `weak` 时,**必须合循环**处理失败;使用 `strong` 时,需确保单次操作的语义正确性。 --- #### 6. **总结** - **`weak` + 循环**:高性能无锁结构的黄金组合。 - **`strong`**:确定性场景的简化选择。 - **跨平台**:在 x86 上两者性能接近,在 ARM 等平台需谨慎选择[^1][^2]。 ```cpp // 综合示例:无锁栈的 push 操作 template<typename T> void lock_free_stack<T>::push(const T& data) { node* new_node = new node(data); new_node->next = head.load(); while (!head.compare_exchange_weak(new_node->next, new_node)) { // 处理失败(值冲突或虚假失败) } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值