Swift tương đương với trò chơi @ không đồng bộ hóa của Objective-C là gì?


231

Tôi đã tìm kiếm sách Swift, nhưng không thể tìm thấy phiên bản Swift của @synyncized. Làm cách nào để loại trừ lẫn nhau trong Swift?


1
Tôi sẽ sử dụng một rào cản công văn. Rào cản cung cấp đồng bộ hóa rất rẻ. công văn_barrier_async (). v.v.
Frederick C. Lee

@ FrederickC.Lee, nếu bạn cần một bản ghi để được đồng bộ hóa, chẳng hạn như khi tạo một trình bao bọc cho removeFirst()?
ScottyBlades

Câu trả lời:


183

Bạn có thể sử dụng GCD. Nó dài dòng hơn một chút @synchronized, nhưng hoạt động như một sự thay thế:

let serialQueue = DispatchQueue(label: "com.test.mySerialQueue")
serialQueue.sync {
    // code
}

12
Điều này thật tuyệt, nhưng thiếu khả năng nhập lại mà bạn có với @ không đồng bộ.
Thác Michael

9
Với phương pháp này bạn cần cẩn thận. Khối của bạn có thể được thực thi trên một số chủ đề khác. Các tài liệu API cho biết: "Là một tối ưu hóa, chức năng này gọi khối trên luồng hiện tại khi có thể."
sinh học

20
Bài viết tuyệt vời từ Matt Gallagher về điều này: cocoawithlove.com/blog/2016/06/02/threads-and-mutexes.html
wuf810

4
Không, điều này gây ra bế tắc thường xuyên.
Tom Kraina

70
Không, không và không. Đẹp thử, nhưng hoạt động không hoàn hảo tốt. Tại sao? Đọc cần thiết (so sánh toàn diện các lựa chọn thay thế, thận trọng) và khung tiện ích tuyệt vời từ Matt Gallagher, tại đây: cocoawithlove.com/blog/2016/06/02/threads-and-mutexes.html @ wuf810 đã đề cập đến điều này đầu tiên (HT), nhưng understated làm thế nào tốt bài viết này là. Tất cả nên đọc. (Vui lòng nâng mức này ở mức tối thiểu để hiển thị ban đầu, nhưng không còn nữa.)
t0rst

181

Tôi đã tự mình tìm kiếm điều này và đi đến kết luận rằng không có cấu trúc bản địa nào bên trong nhanh chóng cho việc này.

Tôi đã tạo nên chức năng trợ giúp nhỏ này dựa trên một số mã tôi đã thấy từ Matt Bridges và những người khác.

func synced(_ lock: Any, closure: () -> ()) {
    objc_sync_enter(lock)
    closure()
    objc_sync_exit(lock)
}

Cách sử dụng khá dễ dàng

synced(self) {
    println("This is a synchronized closure")
}

Có một vấn đề tôi đã tìm thấy với điều này. Chuyển vào một mảng làm đối số khóa dường như gây ra lỗi trình biên dịch rất khó hiểu tại thời điểm này. Nếu không, mặc dù nó dường như làm việc như mong muốn.

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!

Đẹp! Vui lòng gửi một lỗi cho điều đó nếu nó vẫn còn là một vấn đề trong 1.0
MattD

14
Điều này khá hữu ích và duy trì cú pháp của @synchronizedkhối một cách độc đáo, nhưng lưu ý rằng nó không giống với câu lệnh khối dựng sẵn thực sự như @synchronizedkhối trong Objective-C, bởi vì returnvà các breakcâu lệnh không còn hoạt động để nhảy ra khỏi hàm / vòng lặp xung quanh như nó sẽ là nếu đây là một tuyên bố bình thường.
newacct

3
Lỗi có thể là do các mảng được truyền dưới dạng giá trị không phải là tham chiếu
james_alvarez

9
Đây có lẽ sẽ là một nơi tuyệt vời để sử dụng defertừ khóa mới để đảm bảo objc_sync_exitđược gọi ngay cả khi closureném.
devios1

3
@ t0rst Gọi câu trả lời này là "thiếu sót" dựa trên bài viết được liên kết đến không hợp lệ. Bài báo nói rằng phương pháp này "chậm hơn một chút so với lý tưởng" và "bị giới hạn trong các nền tảng của Apple". Điều đó không làm cho nó "thiếu sót" bởi một cú sút xa.
RenniePet

151

Tôi thích và sử dụng nhiều câu trả lời ở đây, vì vậy tôi sẽ chọn cách nào phù hợp nhất với bạn. Điều đó nói rằng, phương pháp tôi thích khi tôi cần một cái gì đó như object-c @synchronizedsử dụng defercâu lệnh được giới thiệu trong swift 2.

{ 
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }

    //
    // code of critical section goes here
    //

} // <-- lock released when this block is exited

Những điều tốt đẹp về phương pháp này, là phần quan trọng của bạn có thể thoát khỏi khối chứa trong bất kỳ thời trang mong muốn (ví dụ return, break, continue, throw), và "những điều khoản trong tuyên bố Hoãn được thực hiện không có vấn đề kiểm soát chương trình được chuyển giao như thế nào." 1


Tôi nghĩ rằng đây có lẽ là giải pháp thanh lịch nhất được cung cấp ở đây. Cảm ơn phản hồi của bạn.
Scott D

3
lockgì Làm thế nào được lockkhởi tạo?
Văn Du Trần

6
locklà bất kỳ đối tượng mục tiêu-c.
ɲeuroburɳ

1
Thông minh! Tôi đã viết một số phương thức trợ giúp khóa khi Swift 1 được giới thiệu và đã không xem lại chúng trong một thời gian. Hoàn toàn quên về trì hoãn; Đây là con đường để đi!
Randy

Tôi thích điều này nhưng gặp lỗi trình biên dịch "Khối lệnh được sắp xếp là một bao đóng không được sử dụng" trong Xcode 8. Ah tôi hiểu rồi, chúng chỉ là dấu ngoặc hàm - quá lâu để tìm liên kết tham chiếu "1" của bạn - cảm ơn!
Duncan Groenewald

83

Bạn có thể tuyên bố sandwich giữa objc_sync_enter(obj: AnyObject?)objc_sync_exit(obj: AnyObject?). Từ khóa @synyncized đang sử dụng các phương thức đó trong trang bìa. I E

objc_sync_enter(self)
... synchronized code ...
objc_sync_exit(self)

3
Điều này có được coi là sử dụng API riêng của Apple không?
Drux

2
Không, objc_sync_enterobjc_sync_exitlà các phương thức được định nghĩa trong Objc-sync.h và là nguồn mở: opensource.apple.com/source/objc4/objc4-371.2/r
nb / đấm

Điều gì xảy ra nếu nhiều luồng cố gắng truy cập vào cùng một tài nguyên, liệu thứ hai có chờ, thử lại hoặc gặp sự cố không?
TruMan1

Thêm vào những gì @bontoJR đã nói, objc_sync_enter(…)objc_sync_exit(…)là các tiêu đề công khai được cung cấp bởi iOS / macOS / vv. API (có vẻ như chúng nằm trong ….sdkđường dẫn usr/include/objc/objc-sync.h) . Cách dễ nhất để tìm hiểu xem có thứ gì đó là API công khai hay không là (trong Xcode) nhập tên hàm (ví dụ: các objc_sync_enter()đối số không cần được chỉ định cho các hàm C) , sau đó thử nhấp vào lệnh. Nếu nó hiển thị cho bạn tệp tiêu đề cho API đó, thì bạn vẫn ổn (vì bạn sẽ không thể xem tiêu đề nếu nó không công khai) .
Slipp D. Thompson

75

Tương tự của lệnh @synchronizedtừ Objective-C có thể có kiểu trả về tùy ý và rethrowshành vi đẹp trong Swift.

// Swift 3
func synchronized<T>(_ lock: AnyObject, _ body: () throws -> T) rethrows -> T {
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }
    return try body()
}

Việc sử dụng defercâu lệnh cho phép trả về trực tiếp một giá trị mà không đưa ra một biến tạm thời.


Trong Swift 2, thêm @noescapethuộc tính vào bao đóng để cho phép tối ưu hóa hơn:

// 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()
}

Dựa trên các câu trả lời từ GNewc [1] (nơi tôi thích kiểu trả về tùy ý) và Tod Castyham [2] (nơi tôi thích defer).


Xcode đang nói với tôi rằng @noescape hiện mặc định và không được dùng trong Swift 3.
RenniePet

Đúng vậy, mã trong câu trả lời này là dành cho Swift 2 và yêu cầu một số điều chỉnh cho Swift 3. Tôi sẽ cập nhật nó khi tôi có thời gian.
werediver

1
Bạn có thể giải thích việc sử dụng? Có lẽ với một ví dụ .. cảm ơn trước! Trong trường hợp của tôi, tôi có một Bộ mà tôi cần phải đồng bộ hóa, bởi vì tôi thao tác nội dung của nó trong một DispatchQueue.
sancho

@sancho Tôi muốn giữ bài viết này súc tích. Bạn dường như hỏi về hướng dẫn lập trình đồng thời chung, đó là một câu hỏi rộng. Hãy thử hỏi nó như một câu hỏi riêng biệt!
werediver

41

Chuyển 4

Trong Swift 4, bạn có thể sử dụng GCD gửi hàng đợi để khóa tài nguyên.

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 }
        }
    }
} 

Điều này dường như không hoạt động với XCode8.1. .serialdường như là không có Nhưng .concurrentcó sẵn. : /
Travis Griggs

2
mặc định là .serial
Duncan Groenewald

2
Lưu ý rằng mẫu này không bảo vệ đúng cách đối với hầu hết các vấn đề đa luồng phổ biến. Ví dụ: nếu bạn chạy myObject.state = myObject.state + 1đồng thời, nó sẽ không tính tổng số thao tác mà thay vào đó mang lại giá trị không xác định. Để giải quyết vấn đề đó, mã cuộc gọi nên được bọc trong một hàng đợi nối tiếp để cả việc đọc và ghi xảy ra nguyên tử. Tất nhiên Obj-c @synchronisedcó cùng một vấn đề, vì vậy theo nghĩa đó, việc thực hiện của bạn là chính xác.
Berik

1
Có, myObject.state += 1là sự kết hợp của đọc và sau đó là thao tác ghi. Một số luồng khác vẫn có thể đi vào giữa để đặt / ghi giá trị. Theo objc.io/blog/2018/12/18/atomic-variables , việc chạy setkhối / đóng đồng bộ thay vào đó sẽ không dễ dàng hơn và không phải dưới biến.
CyberMew

24

Sử dụng câu trả lời của Bryan McLemore, tôi đã mở rộng nó để hỗ trợ các đối tượng ném vào một trang viên an toàn với khả năng trì hoãn Swift 2.0.

func synchronized( lock:AnyObject, block:() throws -> Void ) rethrows
{
    objc_sync_enter(lock)
    defer {
        objc_sync_exit(lock)
    }

    try block()
}

Sẽ tốt hơn nếu sử dụng rethrowsđể đơn giản hóa việc sử dụng với các lần đóng không ném (không cần sử dụng try), như thể hiện trong câu trả lời của tôi .
werediver

23

Để thêm chức năng trả về, bạn có thể làm điều này:

func synchronize<T>(lockObj: AnyObject!, closure: ()->T) -> T
{
  objc_sync_enter(lockObj)
  var retVal: T = closure()
  objc_sync_exit(lockObj)
  return retVal
}

Sau đó, bạn có thể gọi nó bằng cách sử dụng:

func importantMethod(...) -> Bool {
  return synchronize(self) {
    if(feelLikeReturningTrue) { return true }
    // do other things
    if(feelLikeReturningTrueNow) { return true }
    // more things
    return whatIFeelLike ? true : false
  }
}

10

Swift 3

Mã này có khả năng nhập lại và có thể hoạt động với các lệnh gọi hàm không đồng bộ. Trong mã này, sau khi một sốAsyncFunc () được gọi, một hàm đóng khác trên hàng đợi nối tiếp sẽ xử lý nhưng bị chặn bởi semaphore.wait () cho đến khi tín hiệu () được gọi. InternalQueue.sync không nên được sử dụng vì nó sẽ chặn luồng chính nếu tôi không nhầm.

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 không phải là một ý tưởng tốt mà không xử lý lỗi.


Xử lý lỗi gì? Trình biên dịch sẽ không cho phép bất cứ thứ gì ném. Mặt khác, bằng cách không sử dụng objc_sync_enter / exit, bạn từ bỏ một số hiệu suất đáng kể.
gnasher729

8

Trong phiên "Tìm hiểu sự cố và Nhật ký sự cố" phiên 414 của WWDC 2018, họ trình bày cách sau bằng cách sử dụng DispatchQueues với đồng bộ hóa.

Trong swift 4 nên giống như sau:

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
          }
        }
    }
}

Dù sao, bạn cũng có thể đọc nhanh hơn bằng cách sử dụng hàng đợi đồng thời với các rào cản. Việc đọc đồng bộ hóa và không đồng bộ được thực hiện đồng thời và viết một giá trị mới chờ các hoạt động trước đó kết thúc.

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
        }
    }
}

bạn có thể không cần chặn đọc và làm chậm hàng đợi bằng cách sử dụng đồng bộ hóa. Bạn chỉ có thể sử dụng đồng bộ hóa để viết nối tiếp.
Basheer_CAD

6

Sử dụng NSLock trong Swift4:

let lock = NSLock()
lock.lock()
if isRunning == true {
        print("Service IS running ==> please wait")
        return
} else {
    print("Service not running")
}
isRunning = true
lock.unlock()

Cảnh báo Lớp NSLock sử dụng các luồng POSIX để thực hiện hành vi khóa của nó. Khi gửi tin nhắn mở khóa đến một đối tượng NSLock, bạn phải chắc chắn rằng tin nhắn đó được gửi từ cùng một chủ đề đã gửi tin nhắn khóa ban đầu. Mở khóa từ một luồng khác nhau có thể dẫn đến hành vi không xác định.



6

Trong Swift 5 hiện đại, với khả năng quay trở lại:

/**
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()
}

Sử dụng nó như thế này, để tận dụng khả năng giá trị trả về:

let returnedValue = synchronized(self) { 
     // Your code here
     return yourCode()
}

Hoặc như thế khác:

synchronized(self) { 
     // Your code here
    yourCode()
}

2
Đây là câu trả lời đúng và không phải là câu trả lời được chấp nhận và đánh giá cao (phụ thuộc vào GCD). Có vẻ như về cơ bản không ai sử dụng hoặc hiểu cách sử dụng Thread. Tôi hài lòng với nó - trong khi GCDđầy những vấn đề và giới hạn.
javadba

4

Hãy thử: NSRecursiveLock

Một khóa có thể được mua lại nhiều lần bởi cùng một chủ đề mà không gây ra bế tắc.

let lock = NSRecursiveLock()

func f() {
    lock.lock()
    //Your Code
    lock.unlock()
}

func f2() {
    lock.lock()
    defer {
        lock.unlock()
    }
    //Your Code
}

2

Hình tôi sẽ đăng triển khai Swift 5 của mình, dựa trên các câu trả lời trước. Cảm ơn các bạn! Tôi thấy thật hữu ích khi có một cái cũng trả về một giá trị, vì vậy tôi có hai phương thức.

Đây là một lớp đơn giản để thực hiện đầu tiên:

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()
    }
}

Sau đó sử dụng nó như vậy nếu cần một giá trị trả về:

return Sync.syncedReturn(self, closure: {
    // some code here
    return "hello world"
})

Hoặc là:

Sync.synced(self, closure: {
    // do some work synchronously
})

Hãy thử public class func synced<T>(_ lock: Any, closure: () -> T), làm việc cho cả hai, void và bất kỳ loại nào khác. Ngoài ra còn có các công cụ thoái lui.
hnh

@hnh bạn có ý gì bởi những thứ hối hận? Ngoài ra, nếu bạn sẵn sàng chia sẻ một cuộc gọi ví dụ đến phương thức chung với loại <T> sẽ giúp tôi cập nhật câu trả lời - Tôi thích nơi bạn sẽ đi với điều đó.
TheJeff

rethrows, không mọc lại, srz
hnh

1

Chi tiết

xCode 8.3.1, nhanh chóng 3.1

Bài tập

Đọc giá trị ghi từ các chủ đề khác nhau (không đồng bộ).

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)"
    }
}

Sử dụng

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
}

Mẫu đầy đủ

mở rộng công văn

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()
        }
    }
}

lớp ViewContoder

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)")
        }
    }
}

1

Với trình bao bọc tài sản của Swift, đây là những gì tôi đang sử dụng:

@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
    }
}

Sau đó, bạn có thể làm:

@NCCSerialized var foo: Int = 10

hoặc là

@NCCSerialized var myData: [SomeStruct] = []

Sau đó truy cập vào biến như bạn thường làm.


1
Tôi thích giải pháp này, nhưng tò mò về chi phí của mọi người @Decorating kể từ khi làm như vậy có tác dụng phụ là tạo ra một DispatchQueuethứ bị ẩn khỏi người dùng. Tôi tìm thấy tài liệu tham khảo SO này để giúp tôi thoải mái: stackoverflow.com/a/35022486/1060314
Adam Venturella

Bản thân trình bao bọc tài sản khá nhẹ - chỉ là một cấu trúc, vì vậy, một trong những điều nhẹ nhất bạn có thể thực hiện. Cảm ơn các liên kết trên DispatchQueue mặc dù. Tôi đã có ý định thực hiện một số thử nghiệm hiệu năng trên gói queue.sync so với các giải pháp khác (và so với không có hàng đợi), nhưng đã không làm như vậy.
vẽ

1

Tóm lại, Ở đây đưa ra cách phổ biến hơn bao gồm giá trị trả về hoặc khoảng trống và ném

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()
    }


}

0

Tại sao làm cho nó khó khăn và rắc rối với ổ khóa? Sử dụng hàng rào công văn.

Một rào cản công văn tạo ra một điểm đồng bộ hóa trong một hàng đợi đồng thời.

Trong khi nó đang chạy, không có khối nào khác trên hàng đợi được phép chạy, ngay cả khi nó đồng thời và các lõi khác có sẵn.

Nếu đó là âm thanh như một khóa độc quyền (ghi), nó là. Các khối không rào cản có thể được coi là khóa chia sẻ (đọc).

Miễn là tất cả quyền truy cập vào tài nguyên được thực hiện thông qua hàng đợi, các rào cản cung cấp đồng bộ hóa rất rẻ.


2
Ý tôi là, bạn đang giả sử sử dụng hàng đợi GCD để đồng bộ hóa quyền truy cập, nhưng điều đó không được đề cập trong câu hỏi ban đầu. Và một rào cản chỉ cần thiết với hàng đợi đồng thời - bạn chỉ cần sử dụng hàng đợi nối tiếp để xếp hàng các khối loại trừ lẫn nhau để mô phỏng khóa.
Bill

Câu hỏi của tôi, tại sao giả lập một khóa? Từ những gì tôi đọc được, các khóa không được khuyến khích do chi phí quá cao so với rào cản trong hàng đợi.
Frederick C. Lee

0

Dựa trên ɲeuroburɳ , kiểm tra trường hợp của lớp con

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()

Đầu ra:

1
2
3
11
22
33

0

Clark_barrier_async là cách tốt hơn, trong khi không chặn luồng hiện tại.

Clark_barrier_async (accessQueue, {dictionary [object.ID] = object})


-5

Một phương pháp khác là tạo ra một siêu lớp và sau đó kế thừa nó. Bằng cách này bạn có thể sử dụng GCD trực tiếp hơn

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
        }
    }

10
-1 Kế thừa cung cấp cho bạn tính đa hình của kiểu con để đổi lấy việc tăng khớp nối. Tránh sau này nếu bạn không cần cái trước. Đừng lười biếng. Thích thành phần để tái sử dụng mã.
Jano
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.