axiom-synchronization by charleswiltgen/axiom
npx skills add https://github.com/charleswiltgen/axiom --skill axiom-synchronization当 Actor 模型速度过慢或过于重量级时,可使用的底层同步原语。
| 需求 | 使用 | 原因 |
|---|---|---|
| 微秒级操作 | 互斥锁 | 无异步跳转开销 |
| 保护单个属性 | 互斥锁 | 更简单、更快 |
| 复杂的异步工作流 | Actor | 正确处理挂起 |
| 需要挂起点 | Actor | 互斥锁无法挂起 |
| 跨模块共享 | 互斥锁 | 可发送,无需等待 |
| 高频计数器 | 原子操作 | 无锁性能 |
import Synchronization
let mutex = Mutex<Int>(0)
// 读取
let value = mutex.withLock { $0 }
// 写入
mutex.withLock { $0 += 1 }
// 非阻塞尝试
if let value = mutex.withLockIfAvailable({ $0 }) {
// 获取了锁
}
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
特性 :
Sendable —— 可安全跨并发边界共享import os
let lock = OSAllocatedUnfairLock(initialState: 0)
// 基于闭包(推荐)
lock.withLock { state in
state += 1
}
// 传统方式(仅限同一线程)
lock.lock()
defer { lock.unlock() }
// 访问受保护状态
特性 :
Sendableimport Synchronization
let counter = Atomic<Int>(0)
// 原子递增
counter.wrappingAdd(1, ordering: .relaxed)
// 比较并交换
let (exchanged, original) = counter.compareExchange(
expected: 0,
desired: 42,
ordering: .acquiringAndReleasing
)
final class Counter: Sendable {
private let mutex = Mutex<Int>(0)
var value: Int { mutex.withLock { $0 } }
func increment() { mutex.withLock { $0 += 1 } }
}
final class ThreadSafeValue<T: Sendable>: @unchecked Sendable {
private let mutex: Mutex<T>
init(_ value: T) { mutex = Mutex(value) }
var value: T {
get { mutex.withLock { $0 } }
set { mutex.withLock { $0 = newValue } }
}
}
actor ImageCache {
// 使用互斥锁实现无需 Actor 跳转的快速同步读取
private let mutex = Mutex<[URL: Data]>([:])
nonisolated func cachedSync(_ url: URL) -> Data? {
mutex.withLock { $0[url] }
}
func cacheAsync(_ url: URL, data: Data) {
mutex.withLock { $0[url] = data }
}
}
final class FastCounter: Sendable {
private let _value = Atomic<Int>(0)
var value: Int { _value.load(ordering: .relaxed) }
func increment() {
_value.wrappingAdd(1, ordering: .relaxed)
}
}
#if compiler(>=6.0)
import Synchronization
typealias Lock<T> = Mutex<T>
#else
import os
// 为 iOS 16-17 使用 OSAllocatedUnfairLock
#endif
// ❌ 死锁风险
mutex.withLock {
await someAsyncWork() // 任务在持有锁时挂起!
}
// ✅ 安全:在等待前释放锁
let value = mutex.withLock { $0 }
let result = await process(value)
mutex.withLock { $0 = result }
Swift 的协作式线程池具有有限的线程数。阻塞原语会耗尽线程池:
// ❌ 危险:阻塞协作式线程
let semaphore = DispatchSemaphore(value: 0)
Task {
semaphore.wait() // 线程被阻塞,无法运行其他任务!
}
// ✅ 改用异步延续
await withCheckedContinuation { continuation in
// 非阻塞回调
callback { continuation.resume() }
}
切勿在 Swift 中直接使用 os_unfair_lock —— 它可能在内存中移动:
// ❌ 未定义行为:锁可能移动
var lock = os_unfair_lock()
os_unfair_lock_lock(&lock) // 地址可能无效
// ✅ 使用 OSAllocatedUnfairLock(堆分配,地址稳定)
let lock = OSAllocatedUnfairLock()
需要同步?
├─ 需要无锁操作?
│ └─ 简单计数器/标志? → 原子操作
│ └─ 复杂状态? → 互斥锁
├─ 支持 iOS 18+?
│ └─ 是 → 互斥锁
│ └─ 否,支持 iOS 16+? → OSAllocatedUnfairLock
├─ 需要挂起点?
│ └─ 是 → Actor(而非锁)
├─ 需要跨等待访问?
│ └─ 是 → Actor(而非锁)
└─ 性能关键的热路径?
└─ 是 → 互斥锁/原子操作(而非 Actor)
// ❌ 锁不适用于异步操作
let mutex = Mutex<Bool>(false)
Task {
await someWork()
mutex.withLock { $0 = true } // 仍可能出现竞态条件
}
// ✅ 使用 Actor 或异步状态
actor AsyncState {
var isComplete = false
func complete() { isComplete = true }
}
// ❌ 死锁 —— OSAllocatedUnfairLock 是非递归的
lock.withLock {
doWork() // 如果 doWork() 也调用 withLock → 死锁
}
// ✅ 重构以避免嵌套加锁
let data = lock.withLock { $0.copy() }
doWork(with: data)
// ❌ 不要混合使用 lock/unlock 和 withLock
lock.lock()
lock.withLock { /* ... */ } // 死锁!
lock.unlock()
// ✅ 选择一种风格
lock.withLock { /* 所有工作在此完成 */ }
| 排序 | 读取 | 写入 | 使用场景 |
|---|---|---|---|
.relaxed | 是 | 是 | 计数器,无依赖关系 |
.acquiring | 是 | - | 在依赖操作前加载 |
.releasing | - | 是 | 在依赖操作后存储 |
.acquiringAndReleasing | 是 | 是 | 读取-修改-写入 |
.sequentiallyConsistent | 是 | 是 | 最强保证 |
默认选择:计数器使用 .relaxed,读取-修改-写入使用 .acquiringAndReleasing。
文档 : /synchronization, /synchronization/mutex, /os/osallocatedunfairlock
Swift 演进提案 : SE-0433
技能 : axiom-swift-concurrency, axiom-swift-performance
每周安装量
90
代码仓库
GitHub 星标数
601
首次出现
2026年1月21日
安全审计
安装于
opencode76
claude-code71
gemini-cli69
codex69
cursor68
github-copilot65
Low-level synchronization primitives for when actors are too slow or heavyweight.
| Need | Use | Reason |
|---|---|---|
| Microsecond operations | Mutex | No async hop overhead |
| Protect single property | Mutex | Simpler, faster |
| Complex async workflows | Actor | Proper suspension handling |
| Suspension points needed | Actor | Mutex can't suspend |
| Shared across modules | Mutex | Sendable, no await needed |
| High-frequency counters | Atomic | Lock-free performance |
import Synchronization
let mutex = Mutex<Int>(0)
// Read
let value = mutex.withLock { $0 }
// Write
mutex.withLock { $0 += 1 }
// Non-blocking attempt
if let value = mutex.withLockIfAvailable({ $0 }) {
// Got the lock
}
Properties :
Sendable — safe to share across concurrency boundariesimport os
let lock = OSAllocatedUnfairLock(initialState: 0)
// Closure-based (recommended)
lock.withLock { state in
state += 1
}
// Traditional (same-thread only)
lock.lock()
defer { lock.unlock() }
// access protected state
Properties :
Sendableimport Synchronization
let counter = Atomic<Int>(0)
// Atomic increment
counter.wrappingAdd(1, ordering: .relaxed)
// Compare-and-swap
let (exchanged, original) = counter.compareExchange(
expected: 0,
desired: 42,
ordering: .acquiringAndReleasing
)
final class Counter: Sendable {
private let mutex = Mutex<Int>(0)
var value: Int { mutex.withLock { $0 } }
func increment() { mutex.withLock { $0 += 1 } }
}
final class ThreadSafeValue<T: Sendable>: @unchecked Sendable {
private let mutex: Mutex<T>
init(_ value: T) { mutex = Mutex(value) }
var value: T {
get { mutex.withLock { $0 } }
set { mutex.withLock { $0 = newValue } }
}
}
actor ImageCache {
// Mutex for fast sync reads without actor hop
private let mutex = Mutex<[URL: Data]>([:])
nonisolated func cachedSync(_ url: URL) -> Data? {
mutex.withLock { $0[url] }
}
func cacheAsync(_ url: URL, data: Data) {
mutex.withLock { $0[url] = data }
}
}
final class FastCounter: Sendable {
private let _value = Atomic<Int>(0)
var value: Int { _value.load(ordering: .relaxed) }
func increment() {
_value.wrappingAdd(1, ordering: .relaxed)
}
}
#if compiler(>=6.0)
import Synchronization
typealias Lock<T> = Mutex<T>
#else
import os
// Use OSAllocatedUnfairLock for iOS 16-17
#endif
// ❌ DEADLOCK RISK
mutex.withLock {
await someAsyncWork() // Task suspends while holding lock!
}
// ✅ SAFE: Release before await
let value = mutex.withLock { $0 }
let result = await process(value)
mutex.withLock { $0 = result }
Swift's cooperative thread pool has limited threads. Blocking primitives exhaust the pool:
// ❌ DANGEROUS: Blocks cooperative thread
let semaphore = DispatchSemaphore(value: 0)
Task {
semaphore.wait() // Thread blocked, can't run other tasks!
}
// ✅ Use async continuation instead
await withCheckedContinuation { continuation in
// Non-blocking callback
callback { continuation.resume() }
}
Never useos_unfair_lock directly in Swift — it can be moved in memory:
// ❌ UNDEFINED BEHAVIOR: Lock may move
var lock = os_unfair_lock()
os_unfair_lock_lock(&lock) // Address may be invalid
// ✅ Use OSAllocatedUnfairLock (heap-allocated, stable address)
let lock = OSAllocatedUnfairLock()
Need synchronization?
├─ Lock-free operation needed?
│ └─ Simple counter/flag? → Atomic
│ └─ Complex state? → Mutex
├─ iOS 18+ available?
│ └─ Yes → Mutex
│ └─ No, iOS 16+? → OSAllocatedUnfairLock
├─ Need suspension points?
│ └─ Yes → Actor (not lock)
├─ Cross-await access?
│ └─ Yes → Actor (not lock)
└─ Performance-critical hot path?
└─ Yes → Mutex/Atomic (not actor)
// ❌ Locks don't work with async
let mutex = Mutex<Bool>(false)
Task {
await someWork()
mutex.withLock { $0 = true } // Race condition still possible
}
// ✅ Use actor or async state
actor AsyncState {
var isComplete = false
func complete() { isComplete = true }
}
// ❌ Deadlock — OSAllocatedUnfairLock is non-recursive
lock.withLock {
doWork() // If doWork() also calls withLock → deadlock
}
// ✅ Refactor to avoid nested locking
let data = lock.withLock { $0.copy() }
doWork(with: data)
// ❌ Don't mix lock/unlock with withLock
lock.lock()
lock.withLock { /* ... */ } // Deadlock!
lock.unlock()
// ✅ Pick one style
lock.withLock { /* all work here */ }
| Ordering | Read | Write | Use Case |
|---|---|---|---|
.relaxed | Yes | Yes | Counters, no dependencies |
.acquiring | Yes | - | Load before dependent ops |
.releasing | - | Yes | Store after dependent ops |
.acquiringAndReleasing | Yes | Yes | Read-modify-write |
Default choice : .relaxed for counters, .acquiringAndReleasing for read-modify-write.
Docs : /synchronization, /synchronization/mutex, /os/osallocatedunfairlock
Swift Evolution : SE-0433
Skills : axiom-swift-concurrency, axiom-swift-performance
Weekly Installs
90
Repository
GitHub Stars
601
First Seen
Jan 21, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode76
claude-code71
gemini-cli69
codex69
cursor68
github-copilot65
ESLint迁移到Oxlint完整指南:JavaScript/TypeScript项目性能优化工具
1,600 周安装
Open-AutoGLM Phone Agent:开源AI手机智能体,用自然语言控制安卓/iOS/HarmonyOS设备
553 周安装
Voicebox 开源语音合成与克隆工具:本地化 TTS 工作室,替代 ElevenLabs
548 周安装
AI 代理营销技能集合:33个专业营销技能,涵盖SEO、CRO、文案、付费广告
555 周安装
AI合同审查工具 - 依据谈判手册自动分析条款、标记偏差与商业影响
579 周安装
App Store Connect ASO 审核工具:自动化元数据检查和关键词差距分析
577 周安装
移动应用数据分析指南:ASO优化、关键指标与事件追踪方案
569 周安装
.sequentiallyConsistent| Yes |
| Yes |
| Strongest guarantee |