मैंने स्विफ्ट पुस्तक खोज ली है, लेकिन @synchronized के स्विफ्ट संस्करण को नहीं ढूँढ सकता। मैं स्विफ्ट में आपसी बहिष्कार कैसे करूं?
removeFirst()
?
मैंने स्विफ्ट पुस्तक खोज ली है, लेकिन @synchronized के स्विफ्ट संस्करण को नहीं ढूँढ सकता। मैं स्विफ्ट में आपसी बहिष्कार कैसे करूं?
removeFirst()
?
जवाबों:
आप जीसीडी का उपयोग कर सकते हैं। यह तुलना में थोड़ा अधिक है @synchronized
, लेकिन प्रतिस्थापन के रूप में काम करता है:
let serialQueue = DispatchQueue(label: "com.test.mySerialQueue")
serialQueue.sync {
// code
}
मैं खुद इस की तलाश कर रहा था और इस निष्कर्ष पर आया कि इसके लिए अभी तक स्विफ्ट के अंदर कोई देशी निर्माण नहीं हुआ है।
मैंने मैट ब्रिज और दूसरों से देखे गए कुछ कोड के आधार पर इस छोटे सहायक समारोह का निर्माण किया।
func synced(_ lock: Any, closure: () -> ()) {
objc_sync_enter(lock)
closure()
objc_sync_exit(lock)
}
उपयोग बहुत सीधे आगे है
synced(self) {
println("This is a synchronized closure")
}
एक समस्या है जो मैंने इसके साथ पाई है। सरणी में लॉक तर्क के रूप में पास करना इस बिंदु पर एक बहुत ही अप्रिय कंपाइलर त्रुटि का कारण बनता है। अन्यथा यह इच्छानुसार काम करता है।
Bitcast requires both operands to be pointer or neither
%26 = bitcast i64 %25 to %objc_object*, !dbg !378
LLVM ERROR: Broken function found, compilation aborted!
@synchronized
ब्लॉक के सिंटैक्स को अच्छी तरह से संरक्षित करता है , लेकिन ध्यान दें कि यह एक वास्तविक बिलिन ब्लॉक स्टेटमेंट के समान नहीं है @synchronized
जो ऑब्जेक्टिव-सी में ब्लॉक की तरह है, क्योंकि return
और break
स्टेटमेंट अब आसपास के फ़ंक्शन / लूप से बाहर निकलने के लिए काम नहीं करते हैं यदि यह एक सामान्य कथन होता।
defer
कीवर्ड का उपयोग करने के लिए एक महान स्थान होगा ताकि यह सुनिश्चित किया जा सके objc_sync_exit
कि क्या closure
फेंकता है।
मुझे यहां बहुत से उत्तर पसंद हैं और इसलिए मैं आपके लिए सबसे अच्छा काम करता हूं। उस ने कहा, जिस विधि को मैं पसंद करता हूं जब मुझे ऑब्जेक्टिव-सी की आवश्यकता होती है तो स्विफ्ट 2 में पेश किए @synchronized
गए defer
कथन का उपयोग करता है ।
{
objc_sync_enter(lock)
defer { objc_sync_exit(lock) }
//
// code of critical section goes here
//
} // <-- lock released when this block is exited
इस विधि के बारे अच्छी बात यह है, कि अपने महत्वपूर्ण अनुभाग वांछित किसी भी फैशन में धारक ब्लॉक से बाहर निकल सकते है (जैसे, return
, break
, continue
, throw
), और "आस्थगित करें कथन में बयान चाहे कितना कार्यक्रम नियंत्रण स्थानांतरित कर रहा है क्रियान्वित कर रहे हैं।" 1
lock
? कैसे lock
शुरू किया जाता है?
lock
किसी भी उद्देश्य-सी वस्तु है।
तुम objc_sync_enter(obj: AnyObject?)
और के बीच बयान सैंडविच कर सकते हैं objc_sync_exit(obj: AnyObject?)
। @Synchronized कीवर्ड कवर के तहत उन तरीकों का उपयोग कर रहा है। अर्थात
objc_sync_enter(self)
... synchronized code ...
objc_sync_exit(self)
objc_sync_enter
और objc_sync_exit
ObjC-sync.h में परिभाषित तरीके हैं और खुला स्रोत हैं: opensource.apple.com/source/objc4/objc4-371.2/runtime/...
objc_sync_enter(…)
और objc_sync_exit(…)
iOS / macOS / etc द्वारा प्रदान किए गए सार्वजनिक हेडर हैं। एपीआई (ऐसा लगता है कि वे ….sdk
रास्ते में अंदर हैं usr/include/objc/objc-sync.h
) । यह पता लगाने का सबसे आसान तरीका है कि कुछ सार्वजनिक एपीआई है या नहीं (एक्सकोड में) फ़ंक्शन का नाम टाइप करें (जैसे objc_sync_enter()
, तर्क को सी फ़ंक्शन के लिए निर्दिष्ट करने की आवश्यकता नहीं है) , फिर इसे कमांड-क्लिक करने का प्रयास करें। यदि यह आपको उस एपीआई के लिए हेडर फाइल दिखाता है, तो आप अच्छे हैं (क्योंकि आप हेडर को नहीं देख पाएंगे अगर वह सार्वजनिक नहीं था) ।
@synchronized
ऑब्जेक्टिव-सी से निर्देशन का एनालॉग rethrows
स्विफ्ट में एक मनमाना रिटर्न प्रकार और अच्छा व्यवहार हो सकता है।
// Swift 3
func synchronized<T>(_ lock: AnyObject, _ body: () throws -> T) rethrows -> T {
objc_sync_enter(lock)
defer { objc_sync_exit(lock) }
return try body()
}
defer
स्टेटमेंट का उपयोग अस्थायी वैरिएबल को पेश किए बिना सीधे मान वापस करने की सुविधा देता है।
स्विफ्ट 2 में @noescape
अधिक अनुकूलन की अनुमति देने के लिए बंद करने के लिए विशेषता जोड़ें :
// Swift 2
func synchronized<T>(lock: AnyObject, @noescape _ body: () throws -> T) rethrows -> T {
objc_sync_enter(lock)
defer { objc_sync_exit(lock) }
return try body()
}
GNewc [1] के जवाबों के आधार पर (जहाँ मुझे मनमाना रिटर्न प्रकार पसंद है) और टॉड कनिंघम [2] (जहाँ वह पसंद करता है defer
)।
स्विफ्ट 4
स्विफ्ट 4 में आप संसाधनों को लॉक करने के लिए GCDs प्रेषण कतारों का उपयोग कर सकते हैं।
class MyObject {
private var internalState: Int = 0
private let internalQueue: DispatchQueue = DispatchQueue(label:"LockingQueue") // Serial by default
var state: Int {
get {
return internalQueue.sync { internalState }
}
set (newState) {
internalQueue.sync { internalState = newState }
}
}
}
.serial
लगता है अनुपलब्ध है। लेकिन .concurrent
उपलब्ध है। : /
myObject.state = myObject.state + 1
समवर्ती रूप से भाग लेंगे, तो यह कुल संचालन की गणना नहीं करेगा, बल्कि इसके बजाय एक nondeterministic मान प्राप्त करेगा। उस समस्या को हल करने के लिए, कॉलिंग कोड को एक सीरियल कतार में लपेटा जाना चाहिए ताकि रीड और राइट दोनों परमाणु रूप से हो सकें। बेशक ओब्ज-सी की @synchronised
एक ही समस्या है, इसलिए इस अर्थ में आपका कार्यान्वयन सही है।
myObject.state += 1
रीड का संयोजन है और फिर राइट ऑपरेशन है। कुछ अन्य थ्रेड अभी भी मान सेट करने / लिखने के लिए इनबेटीइन आ सकते हैं। Objc.io/blog/2018/12/18/atomic-variables के अनुसार , set
सिंक ब्लॉक / क्लोजर को चलाने के बजाय इसे चलाने के लिए आसान होगा और चर के तहत नहीं।
वापसी कार्यक्षमता जोड़ने के लिए, आप ऐसा कर सकते हैं:
func synchronize<T>(lockObj: AnyObject!, closure: ()->T) -> T
{
objc_sync_enter(lockObj)
var retVal: T = closure()
objc_sync_exit(lockObj)
return retVal
}
इसके बाद, आप इसका उपयोग करके कॉल कर सकते हैं:
func importantMethod(...) -> Bool {
return synchronize(self) {
if(feelLikeReturningTrue) { return true }
// do other things
if(feelLikeReturningTrueNow) { return true }
// more things
return whatIFeelLike ? true : false
}
}
ब्रायन मैकलमोर उत्तर का उपयोग करते हुए, मैंने इसे उन वस्तुओं का समर्थन करने के लिए बढ़ाया जो स्विफ्ट 2.0 डिफर की क्षमता के साथ एक सुरक्षित मनोर में फेंकते हैं।
func synchronized( lock:AnyObject, block:() throws -> Void ) rethrows
{
objc_sync_enter(lock)
defer {
objc_sync_exit(lock)
}
try block()
}
rethrows
गैर-फेंकने वाले क्लोजर (उपयोग करने की आवश्यकता नहीं try
) के साथ उपयोग को सरल बनाने के लिए उपयोग करना बेहतर होगा , जैसा कि मेरे उत्तर में दिखाया गया है ।
स्विफ्ट 3
इस कोड में फिर से प्रवेश की क्षमता है और यह एसिंक्रोनस फ़ंक्शन कॉल के साथ काम कर सकता है। इस कोड में, someAsyncFunc () को कॉल करने के बाद, सीरियल कतार पर एक और फंक्शन क्लोजर प्रोसेस होगा लेकिन semaphore.wait () द्वारा तब तक ब्लॉक किया जाएगा जब तक सिग्नल () नहीं कहा जाता है। अगर मैं गलत नहीं हूँ तो यह मुख्य धागे को अवरुद्ध कर देगा क्योंकि इंटरन्यू क्यू.सुंक का उपयोग नहीं किया जाना चाहिए।
let internalQueue = DispatchQueue(label: "serialQueue")
let semaphore = DispatchSemaphore(value: 1)
internalQueue.async {
self.semaphore.wait()
// Critical section
someAsyncFunc() {
// Do some work here
self.semaphore.signal()
}
}
objc_sync_enter / objc_sync_exit त्रुटि से निपटने के बिना एक अच्छा विचार नहीं है।
2018 के WWDC के "अंडरस्टैंडिंग क्रैश और क्रैश लॉग" सत्र 414 में वे सिंक के साथ डिस्पैचक्यू का उपयोग करके निम्न तरीके दिखाते हैं।
स्विफ्ट 4 में निम्नलिखित की तरह कुछ होना चाहिए:
class ImageCache {
private let queue = DispatchQueue(label: "sync queue")
private var storage: [String: UIImage] = [:]
public subscript(key: String) -> UIImage? {
get {
return queue.sync {
return storage[key]
}
}
set {
queue.sync {
storage[key] = newValue
}
}
}
}
वैसे भी आप बाधाओं के साथ समवर्ती कतारों का उपयोग करके तेजी से पढ़ सकते हैं। सिंक और एसिंक्स रीड को समवर्ती रूप से निष्पादित किया जाता है और एक नया मान लिखने के लिए पिछले ऑपरेशनों की प्रतीक्षा करता है।
class ImageCache {
private let queue = DispatchQueue(label: "with barriers", attributes: .concurrent)
private var storage: [String: UIImage] = [:]
func get(_ key: String) -> UIImage? {
return queue.sync { [weak self] in
guard let self = self else { return nil }
return self.storage[key]
}
}
func set(_ image: UIImage, for key: String) {
queue.async(flags: .barrier) { [weak self] in
guard let self = self else { return }
self.storage[key] = image
}
}
}
Swift4 में NSLock का उपयोग करें :
let lock = NSLock()
lock.lock()
if isRunning == true {
print("Service IS running ==> please wait")
return
} else {
print("Service not running")
}
isRunning = true
lock.unlock()
चेतावनी NSLock वर्ग अपने लॉकिंग व्यवहार को लागू करने के लिए POSIX थ्रेड्स का उपयोग करता है। NSLock ऑब्जेक्ट को अनलॉक संदेश भेजते समय, आपको यह सुनिश्चित करना चाहिए कि संदेश उसी थ्रेड से भेजा गया है जिसने प्रारंभिक लॉक संदेश भेजा था। एक अलग धागे से ताला खोलने से अपरिभाषित व्यवहार हो सकता है।
आधुनिक स्विफ्ट 5 में, वापसी क्षमता के साथ:
/**
Makes sure no other thread reenters the closure before the one running has not returned
*/
@discardableResult
public func synchronized<T>(_ lock: AnyObject, closure:() -> T) -> T {
objc_sync_enter(lock)
defer { objc_sync_exit(lock) }
return closure()
}
रिटर्न वैल्यू क्षमता का लाभ उठाने के लिए इसका इस तरह उपयोग करें:
let returnedValue = synchronized(self) {
// Your code here
return yourCode()
}
या ऐसा ही अन्यथा:
synchronized(self) {
// Your code here
yourCode()
}
GCD
)। ऐसा लगता है कि अनिवार्य रूप से कोई उपयोग नहीं करता है या समझता है कि कैसे उपयोग करना है Thread
। मैं इसके साथ खुश हूँ - जबकि GCD
गोटे और मर्यादाओं से भरा हुआ है।
कोशिश करें: NSRecursiveLock
एक लॉक जिसे एक ही थ्रेड द्वारा एक गतिरोध पैदा किए बिना कई बार प्राप्त किया जा सकता है।
let lock = NSRecursiveLock()
func f() {
lock.lock()
//Your Code
lock.unlock()
}
func f2() {
lock.lock()
defer {
lock.unlock()
}
//Your Code
}
चित्र मैं अपने स्विफ्ट 5 कार्यान्वयन को पोस्ट करूंगा, पूर्व उत्तरों से निर्मित। धन्यवाद दोस्तों! मुझे ऐसा मददगार लगा जो एक ऐसा मूल्य है जो एक मूल्य भी लौटाता है, इसलिए मेरे पास दो तरीके हैं।
यहाँ पहले बनाने के लिए एक सरल वर्ग है:
import Foundation
class Sync {
public class func synced(_ lock: Any, closure: () -> ()) {
objc_sync_enter(lock)
defer { objc_sync_exit(lock) }
closure()
}
public class func syncedReturn(_ lock: Any, closure: () -> (Any?)) -> Any? {
objc_sync_enter(lock)
defer { objc_sync_exit(lock) }
return closure()
}
}
अगर रिटर्न वैल्यू की जरूरत हो तो इसका इस्तेमाल करें:
return Sync.syncedReturn(self, closure: {
// some code here
return "hello world"
})
या:
Sync.synced(self, closure: {
// do some work synchronously
})
public class func synced<T>(_ lock: Any, closure: () -> T)
, दोनों, शून्य और किसी अन्य प्रकार के लिए काम करता है। रेगो सामान भी है।
xCode 8.3.1, स्विफ्ट 3.1
विभिन्न थ्रेड्स (async) से मूल्य लिखें।
class AsyncObject<T>:CustomStringConvertible {
private var _value: T
public private(set) var dispatchQueueName: String
let dispatchQueue: DispatchQueue
init (value: T, dispatchQueueName: String) {
_value = value
self.dispatchQueueName = dispatchQueueName
dispatchQueue = DispatchQueue(label: dispatchQueueName)
}
func setValue(with closure: @escaping (_ currentValue: T)->(T) ) {
dispatchQueue.sync { [weak self] in
if let _self = self {
_self._value = closure(_self._value)
}
}
}
func getValue(with closure: @escaping (_ currentValue: T)->() ) {
dispatchQueue.sync { [weak self] in
if let _self = self {
closure(_self._value)
}
}
}
var value: T {
get {
return dispatchQueue.sync { _value }
}
set (newValue) {
dispatchQueue.sync { _value = newValue }
}
}
var description: String {
return "\(_value)"
}
}
print("Single read/write action")
// Use it when when you need to make single action
let obj = AsyncObject<Int>(value: 0, dispatchQueueName: "Dispatch0")
obj.value = 100
let x = obj.value
print(x)
print("Write action in block")
// Use it when when you need to make many action
obj.setValue{ (current) -> (Int) in
let newValue = current*2
print("previous: \(current), new: \(newValue)")
return newValue
}
विस्तार डिस्पैचग्रुप
extension DispatchGroup {
class func loop(repeatNumber: Int, action: @escaping (_ index: Int)->(), completion: @escaping ()->()) {
let group = DispatchGroup()
for index in 0...repeatNumber {
group.enter()
DispatchQueue.global(qos: .utility).async {
action(index)
group.leave()
}
}
group.notify(queue: DispatchQueue.global(qos: .userInitiated)) {
completion()
}
}
}
वर्ग ViewController
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//sample1()
sample2()
}
func sample1() {
print("=================================================\nsample with variable")
let obj = AsyncObject<Int>(value: 0, dispatchQueueName: "Dispatch1")
DispatchGroup.loop(repeatNumber: 5, action: { index in
obj.value = index
}) {
print("\(obj.value)")
}
}
func sample2() {
print("\n=================================================\nsample with array")
let arr = AsyncObject<[Int]>(value: [], dispatchQueueName: "Dispatch2")
DispatchGroup.loop(repeatNumber: 15, action: { index in
arr.setValue{ (current) -> ([Int]) in
var array = current
array.append(index*index)
print("index: \(index), value \(array[array.count-1])")
return array
}
}) {
print("\(arr.value)")
}
}
}
स्विफ्ट की संपत्ति के रैपर के साथ, यह वह है जो मैं अभी उपयोग कर रहा हूं:
@propertyWrapper public struct NCCSerialized<Wrapped> {
private let queue = DispatchQueue(label: "com.nuclearcyborg.NCCSerialized_\(UUID().uuidString)")
private var _wrappedValue: Wrapped
public var wrappedValue: Wrapped {
get { queue.sync { _wrappedValue } }
set { queue.sync { _wrappedValue = newValue } }
}
public init(wrappedValue: Wrapped) {
self._wrappedValue = wrappedValue
}
}
तो आप बस कर सकते हैं:
@NCCSerialized var foo: Int = 10
या
@NCCSerialized var myData: [SomeStruct] = []
फिर चर का उपयोग करें जैसा कि आप सामान्य रूप से करेंगे।
DispatchQueue
जो उपयोगकर्ता से छिपा हुआ है। मुझे यह एसओ का संदर्भ मेरे दिमाग को आसान बनाने के लिए मिला: stackoverflow.com/a/35022486/1060314
अंत में, यहां अधिक सामान्य तरीका दिया गया है जिसमें रिटर्न वैल्यू या शून्य, और थ्रो शामिल हैं
import Foundation
extension NSObject {
func synchronized<T>(lockObj: AnyObject!, closure: () throws -> T) rethrows -> T
{
objc_sync_enter(lockObj)
defer {
objc_sync_exit(lockObj)
}
return try closure()
}
}
ताले के साथ यह मुश्किल और परेशानी क्यों है? डिस्पैच बैरियर का उपयोग करें।
एक प्रेषण अवरोध समवर्ती कतार के भीतर एक तुल्यकालन बिंदु बनाता है।
जबकि यह चल रहा है, कतार पर किसी अन्य ब्लॉक को चलाने की अनुमति नहीं है, भले ही यह समवर्ती हो और अन्य कोर उपलब्ध हों।
यदि यह एक विशेष (लिखने) लॉक की तरह लगता है, तो यह है। गैर-अवरोधक ब्लॉकों को साझा (पढ़ा) ताले के रूप में माना जा सकता है।
जब तक संसाधन के सभी उपयोग कतार के माध्यम से किए जाते हैं, तब तक बाधाएं बहुत सस्ती सिंक्रनाइज़ेशन प्रदान करती हैं।
Oneuroburɳ के आधार पर , एक उप-श्रेणी के मामले का परीक्षण करें
class Foo: NSObject {
func test() {
print("1")
objc_sync_enter(self)
defer {
objc_sync_exit(self)
print("3")
}
print("2")
}
}
class Foo2: Foo {
override func test() {
super.test()
print("11")
objc_sync_enter(self)
defer {
print("33")
objc_sync_exit(self)
}
print("22")
}
}
let test = Foo2()
test.test()
1
2
3
11
22
33
एक और तरीका है एक सुपरक्लास बनाना और फिर उसे विरासत में देना। इस तरह आप जीसीडी का अधिक सीधे उपयोग कर सकते हैं
class Lockable {
let lockableQ:dispatch_queue_t
init() {
lockableQ = dispatch_queue_create("com.blah.blah.\(self.dynamicType)", DISPATCH_QUEUE_SERIAL)
}
func lock(closure: () -> ()) {
dispatch_sync(lockableQ, closure)
}
}
class Foo: Lockable {
func boo() {
lock {
....... do something
}
}