You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
AtomicRepresentation には Int しかありませんが整数という形式に考えをとらわれる必要はありません。1wordにデータが収まるか収まらないか、ただそれだけです。変換や圧縮をした結果1word以内の長さに収まれば Atomic で扱うことができます。AtomicRepresentable | Apple Developer Documentationには列挙型を対応させる例が載っています。
enumTrafficLight:UInt8{case red
case yellow
case green
}extensionTrafficLight:AtomicRepresentable{}
アンダースコアで区切られたうちの最初の単語がLLVM IRの命令の名前です。つまりLLVMの公式ドキュメントを zext や shl や or で検索すればどんなことをする命令なのかがわかります。例えば zext で調べると次の命令が見つかります。
‘zext .. to’ Instruction
Syntax:
<result> = zext <ty> <value> to <ty2>
Semantics:
The zext fills the high order bits of the value with zero bits until it reaches the size of the destination type, ty2.
Perform an atomic weak compare and exchange operation on the current value, applying the memory ordering. This compare-exchange variant is allowed to spuriously fail; it is designed to be called in a loop until it indicates a successful exchange has happened.
extensionAtomicwhere Value ==Int64{func add(...){...}func store(...){...}
他のメソッドの実装が続く...}extensionAtomicwhere Value ==Int32{...}
Int16やInt8やUIntも実装しなくちゃ...
こう書けたら最高ですね!:
extensionAtomicwhere Value == ${ここにいろんなIntが入る}{func ${ここにいろんなメソッド名が入る}(...){BuiltIn.${メソッドに対応するLLVMの命令の名前が入る}(...)}}
SwiftコンパイラはXXX.swift.gybというテンプレートファイルを使って類似の実装を量産することができます。gybとはGenerate Your Boilerplateの略です。 Atomic 以外でもさまざまな場所でさまざまな実装を量産しています。
extension Atomic where Value == ${intType} {
% for (name, builtinName, op, doc) in integerOperations:
for文で integerOperations を回してメソッドを量産します。
% for (name, builtinName, op, doc) in integerOperations:
/// Perform an atomic ${doc} operation and return the old and new value,
/// applying the specified memory ordering.
〜〜途中省略〜〜
public func ${lowerFirst(name)}(
_ operand: ${intType},
ordering: AtomicUpdateOrdering
) -> (oldValue: ${intType}, newValue: ${intType}) {
〜〜途中省略〜〜
Builtin.atomicrmw_${atomicOperationName(intType, builtinName)}_${llvmOrder}_Int64(
_rawAddress,
operand._value
)
An acquiring update synchronizes with a releasing operation whose value its reads. It ensures that the releasing and acquiring threads agree that all subsequent variable accesses on the acquring thread happen after the atomic operation itself.
letcounter=Atomic(0)varordering=AtomicUpdateOrdering.relaxed
counter.wrappingAdd(1, ordering: ordering) // ❗️Ordering argument must be a static method or property of 'AtomicUpdateOrdering'
引数で受け取ったものを渡すのもNGです。
func method(ordering:AtomicUpdateOrdering){letcounter=Atomic(0)
counter.wrappingAdd(1, ordering: ordering) // ❗️Ordering argument must be a static method or property of 'AtomicUpdateOrdering'
}
However, it’s unsafe to use os_unfair_lock from Swift because it’s a value type and, therefore, doesn’t have a stable memory address. That means when you call os_unfair_lock_lock or os_unfair_lock_unlock and pass a lock object using the & operator, the system may lock or unlock the wrong object.
Instead, use OSAllocatedUnfairLock, which avoids that pitfall because it doesn’t function as a value type, despite being a structure. All copied instances of an OSAllocatedUnfairLock control the same underlying lock allocation.
structMyValue:~Copyable {}letvalue0=MyValue()letvalue1= value0 // ❗️ Cannot consume noncopyable stored property 'value0' that is global
print(value0 is Copyable) // ⚠️ Cast from 'MyValue' to unrelated type 'any Copyable' always fails / ❗️ Noncopyable types cannot be conditionally cast