preface

Recently, I tried to use the fence function in Swift, but I found it difficult to write how to call it. I did a little research before I knew how to use it. So let’s just review the fence function.

Hi 👋

  • Wechat: RyukieW
  • Wechat official account: LabLawliet
  • 📦 Archive of technical articles
  • 🐙 making
My personal project Minesweeper Elic Endless Ladder Dream of books
type The game financial
AppStore Elic Umemi

What is the fence function

Dispatch Barrier

Let’s take a look at the official documentation definition: the synchronization point of a task executed in a concurrent scheduling queue

Speaking: Can control the execution order of concurrent tasks

1.1 Common apis

  • dispatch_barrier_async
    • This will not be executed until the previous tasks are completed
  • dispatch_barrier_sync
    • Block the thread until the previous task is complete, and then the next task is executed

Let’s see how it works in practice

How to write the barrier function in Swift

The dispatch_barrier_async/dispatch_barrier_sync apis are not usable.

2.1 Creating a Concurrent Queue

As prompted, we create a queue:

let queue = DispatchQueue.init(label: "RyukieQueue", qos: .default, attributes: .concurrent, autoreleaseFrequency: .workItem, target: nil)
Copy the code
  • parameter
    • label
      • The queue name
    • qos
      • priority
    • attributes
      • Property list, where synchronous asynchrony can be set (added.concurrentConcurrent collating, otherwise traversing queue)
    • autoreleaseFrequency
      • Frequency of brake release in block
    • target
      • Which pair of columns do you want the block to be executed on? The default is the current pair

2.2 Creating the fence function

Discover the API through documentation

  • parameter
    • group
      • Scheduling group
    • qos
      • priority
    • flags
      • Additional property, which can be set here as a fence function
    • work
      • block
queue.async(group: nil, qos: .default, flags: .barrier) {
    xxx
}
Copy the code

Asynchronous fence function + custom queue

let queue = DispatchQueue.init(label: "RyukieQueue", qos: .default, attributes: .concurrent, autoreleaseFrequency: .workItem, target: nil)
        
queue.async {
    print("1: \(Thread.current)")
    sleep(1)}// The asynchronous fence function
queue.async(group: nil, qos: .default, flags: .barrier) {
    print("barrier - async: \(Thread.current)")
    for _ in 0.100 {
        print("...")
    }
}

queue.async {
    print("2: \(Thread.current)")
}

queue.async {
    print("3.\(Thread.current)")
}

queue.async {
    print("4: \(Thread.current)")}print("= = = = = = = = = :\(Thread.current)")
Copy the code

What do you think is going to happen with this code?

Output:

1: <NSThread: 0x6000018f1040>{number = 6, name = (null)} =========: <NSThread: 0x6000018b0800>{number = 1, name = main} barrier - async: <NSThread: 0x6000018f1040>{number = 6, name = (null)} ... . . 4: <NSThread: 0x6000018f6fc0>{number = 4, name = (null)} 3: <NSThread: 0x6000018f0540>{number = 5, name = (null)} 2: <NSThread: 0x6000018f1040>{number = 6, name = (null)}Copy the code

3.1 Process Analysis

  • The blue line represents the order in which the code is executed
  • 2/3/4 Asynchronous task sequencing is not always easy to understand
  • The queue existsAsynchronous fence functionTasks after it will not be scheduled
  • = = = = = =Is code outside the queue, so it is not affectedAsynchronous fence functionImpact, because other tasks are asynchronous, its output position is not necessarily but the maximum probability is inAsynchronous fence functionBefore performing

Synchronous fence function + custom queue

Code tweaks:

let queue = DispatchQueue.init(label: "RyukieQueue", qos: .default, attributes: .concurrent, autoreleaseFrequency: .workItem, target: nil)
        
queue.async {
    print("1: \(Thread.current)")
    sleep(1)}// synchronize the fence function
queue.sync(flags: .barrier) {
    print("barrier - sync: \(Thread.current)")
    for _ in 0.100 {
        print("...")
    }
}

queue.async {
    print("2: \(Thread.current)")
}

queue.async {
    print("3.\(Thread.current)")
}

queue.async {
    print("4: \(Thread.current)")}print("= = = = = = = = = :\(Thread.current)")
Copy the code

What do you think is going to happen with this code?

Output:

1: <NSThread: 0x6000038b3640>{number = 13, name = (null)} barrier - sync: <NSThread: 0x6000038f83c0>{number = 1, name = main} ... . . . . . . =========: <NSThread: 0x6000038f83c0>{number = 1, name = main} 2: <NSThread: 0x6000038b3640>{number = 13, name = (null)} 4: <NSThread: 0x6000038b3640>{number = 13, name = (null)} 3: <NSThread: 0x6000038ddb00>{number = 11, name = (null)}Copy the code

4.1 Process Analysis

  • The blue line represents the order in which the code is executed
  • Synchronous fence function, blocks the execution of thread code in the current code interval
  • As shown in the figure, only whenSynchronous fence functionThe internal tasks are completed before the external subsequent code is continued
  • so= = = = & 2/3/4Must be inSynchronous fence function

5. Global concurrent queues

As mentioned earlier, the fence function can only be used in concurrent queues, but all of the above use custom concurrent queues. Can global concurrent queues be used? Let’s verify that

5.1 Asynchronous fence function + global concurrent queue

Through repeated debugging, it was found that the fence function failed

2: <NSThread: 0x6000026bd280>{number = 7, name = (null)} =========: <NSThread: 0x6000026f0180>{number = 1, name = main} 3: <NSThread: 0x6000026bc540>{number = 3, name = (null)} 1: <NSThread: 0x6000026be080>{number = 6, name = (null)} 4: <NSThread: 0x6000026f1bc0>{number = 5, name = (null)} barrier - async: <NSThread: 0x6000026bc540>{number = 3, name = (null)} ... . .Copy the code

Now let’s try synchronous

5.2 Synchronous fence function + global concurrent queue

It also loses its original effect

barrier - sync: <NSThread: 0x60000156c800>{number = 1, name = main} ... . . . . =========: <NSThread: 0x60000156c800>{number = 1, name = main} 1: <NSThread: 0x60000152a280>{number = 9, name = (null)} 2: <NSThread: 0x60000152c4c0>{number = 4, name = (null)} 4: <NSThread: 0x600001528700>{number = 10, name = (null)} 3: <NSThread: 0x60000152ec40>{number = 11, name = (null)}Copy the code

5.3 thinking

Global alignment as a global alignment, there will be many tasks, many of which are beyond our control. If blocked, it will lead to many unknown problems. So here the designer makes it six can not use the fence function 👍.

The specific logic can only be answered by the source code, if you are interested in GCD source code: libdispatch explore

reference

  • DispatchQueue
  • GCD source code: libdispatch