How to ensure to run some code on same background thread?

后端 未结 2 489
时光说笑
时光说笑 2020-12-10 07:13

I am using realm in my iOS Swift project. Search involve complex filters for a big data set. So I am fetching records on background thread.

But realm can be used onl

2条回答
  •  一向
    一向 (楼主)
    2020-12-10 07:23

    Here's a small worker class that can works in a similar fashion to async dispatching on a serial queue, with the guarantee that the thread stays the same for all work items.

    // Performs submitted work items on a dedicated thread
    class Worker {
    
        // the worker thread
        private var thread: Thread?
    
        // used to put the worker thread in the sleep mode, so in won't consume
        // CPU while the queue is empty
        private let semaphore = DispatchSemaphore(value: 0)
    
        // using a lock to avoid race conditions if the worker and the enqueuer threads
        // try to update the queue at the same time
        private let lock = NSRecursiveLock()
    
        // and finally, the glorious queue, where all submitted blocks end up, and from
        // where the worker thread consumes them
        private var queue = [() -> Void]()
    
        // enqueues the given block; the worker thread will execute it as soon as possible
        public func enqueue(_ block: @escaping () -> Void) {
            // add the block to the queue, in a thread safe manner
            locked { queue.append(block) }
    
            // signal the semaphore, this will wake up the sleeping beauty
            semaphore.signal()
    
            // if this is the first time we enqueue a block, detach the thread
            // this makes the class lazy - it doesn't dispatch a new thread until the first
            // work item arrives
            if thread == nil {
                thread = Thread(block: work)
                thread?.start()
            }
        }
    
        // the method that gets passed to the thread
        private func work() {
            // just an infinite sequence of sleeps while the queue is empty
            // and block executions if the queue has items
            while true {
                // let's sleep until we get signalled that items are available
                semaphore.wait()
    
                // extract the first block in a thread safe manner, execute it
                // if we get here we know for sure that the queue has at least one element
                // as the semaphore gets signalled only when an item arrives
                let block = locked { queue.removeFirst() }
                block()
            }
        }
    
        // synchronously executes the given block in a thread-safe manner
        // returns the same value as the block
        private func locked(do block: () -> T) -> T {
            lock.lock(); defer { lock.unlock() }
            return block()
        }
    }
    

    Just instantiate it and let it do the job:

    let worker = Worker()
    worker.enqueue { print("On background thread, yay") }
    

提交回复
热议问题