美文网首页归藏
Swift 实现一个 线程安全的数组

Swift 实现一个 线程安全的数组

作者: 半城coding | 来源:发表于2021-08-03 15:30 被阅读0次

    原文地址

    什么是线程安全

    当一段代码被多个线程执行,执行后的结果和多个线程依次执行后的结果一致,那么这段代码就是线程安全的。

    产生线程不安全原因

    1. 线程是抢占执行的。
    2. 有的操作不是原子的。当 cpu 执行一个线程过程时,调度器可能调走CPU,去执行另一个线程,此线程的操作可能还没有结束;(通过锁来解决)
    3. 多个线程尝试修改同一个变量
    4. 内存可变性

    为什么要线程安全

    线程安全是程序能够正确执行并得到预期结果的保证

    数组怎么实现线程安全

    1. NSLock 等互斥锁
    2. GCD barrier
    3. 读写锁(pthread_rwlock_t)

    pthread_rwlock_t 实现数组安全

    import Foundation
    
    // MARK: - ThreadSafeArray
    
    public class ThreadSafeArray<Element> {
        private var array: [Element] = []
        private var lock = pthread_rwlock_t()
    
        public init() {
            let status = pthread_rwlock_init(&lock, nil)
            assert(status == 0)
        }
    
        public convenience init(array: [Element]) {
            self.init()
            self.array = array
        }
        deinit {
            pthread_rwlock_destroy(&lock)
        }
    }
    
    // MARK: - Properties
    
    public extension ThreadSafeArray {
        var first: Element? {
            var result: Element?
            pthread_rwlock_rdlock(&lock)
            result = array.first
            pthread_rwlock_unlock(&lock)
            return result
        }
    
        var last: Element? {
            var result: Element?
            pthread_rwlock_rdlock(&lock)
            result = array.last
            pthread_rwlock_unlock(&lock)
            return result
        }
    
        var count: Int {
            pthread_rwlock_rdlock(&lock)
            let count = array.count
            pthread_rwlock_unlock(&lock)
            return count
        }
    
        var isEmpty: Bool {
            pthread_rwlock_rdlock(&lock)
            let result = (array.count > 0)
            pthread_rwlock_unlock(&lock)
            return result
        }
    
        var description: String {
            pthread_rwlock_rdlock(&lock)
            let str = array.description
            pthread_rwlock_unlock(&lock)
            return str
        }
    }
    
    // MARK: - Immutable
    
    public extension ThreadSafeArray {
        func first(where predicate: (Element)->Bool)->Element? {
            pthread_rwlock_rdlock(&lock)
            let result = array.first(where: predicate)
            pthread_rwlock_unlock(&lock)
            return result
        }
    
        func last(where predicate: (Element)->Bool)->Element? {
            pthread_rwlock_rdlock(&lock)
            let result = array.last(where: predicate)
            pthread_rwlock_unlock(&lock)
            return result
        }
    
        func filter(isIncluded: @escaping (Element)->Bool) ->ThreadSafeArray<Element> {
            pthread_rwlock_rdlock(&lock)
            let result = array.filter(isIncluded)
            pthread_rwlock_unlock(&lock)
            return ThreadSafeArray(array: result)
        }
    
        func index(where predicate: (Element)->Bool)-> Int? {
            pthread_rwlock_rdlock(&lock)
            let result = array.firstIndex(where: predicate)
            pthread_rwlock_unlock(&lock)
            return result
        }
    
        func sorted(by areInIncreasingOrder: (Element, Element)->Bool)->ThreadSafeArray<Element> {
            pthread_rwlock_rdlock(&lock)
            let result = array.sorted(by: areInIncreasingOrder)
            let newArray = ThreadSafeArray<Element>(array: result)
            pthread_rwlock_unlock(&lock)
            return newArray
        }
    
        func map<T>(_ transform: @escaping (Element)->T) ->[T] {
            pthread_rwlock_rdlock(&lock)
            let result = array.map(transform)
            pthread_rwlock_unlock(&lock)
            return result
        }
    
        func compactMap<T>(_ transform: (Element)->T)->[T] {
            pthread_rwlock_rdlock(&lock)
            let result = array.compactMap(transform)
            pthread_rwlock_unlock(&lock)
            return result
        }
    
        func reduce<T>(initialResult: T, _ nexPartialResult: @escaping (T, Element)->T)->T {
            pthread_rwlock_rdlock(&lock)
            let result = array.reduce(initialResult, nexPartialResult)
            pthread_rwlock_unlock(&lock)
            return result
        }
    
        func forEach(_ body: (Element)->Void) {
            pthread_rwlock_rdlock(&lock)
            array.forEach(body)
            pthread_rwlock_unlock(&lock)
        }
    
        func contains(where predicate: (Element)->Bool)->Bool {
            pthread_rwlock_rdlock(&lock)
            let result = array.contains(where: predicate)
            pthread_rwlock_unlock(&lock)
            return result
        }
    
        func allSatisfy(_ predicate: (Element)->Bool)->Bool {
            pthread_rwlock_rdlock(&lock)
            let result = array.allSatisfy(predicate)
            pthread_rwlock_unlock(&lock)
            return result
        }
    }
    
    // MARK: - Mutable
    
    public extension ThreadSafeArray {
        func append(_ element: Element) {
            pthread_rwlock_wrlock(&lock)
            array.append(element)
            pthread_rwlock_unlock(&lock)
        }
    
        func append(_ elements: [Element]) {
            pthread_rwlock_wrlock(&lock)
            array += elements
            pthread_rwlock_unlock(&lock)
        }
    
        func insert(_ element: Element, at index: Int) {
            pthread_rwlock_wrlock(&lock)
            array.insert(element, at: index)
            pthread_rwlock_unlock(&lock)
        }
    
        func remove(at index: Int, completion: ((Element)->Void)? = nil) {
            pthread_rwlock_wrlock(&lock)
            if index > 0, index < count {
                let e = array.remove(at: index)
                completion?(e)
            }
            pthread_rwlock_unlock(&lock)
        }
    
        func remove(where predicate: @escaping (Element)->Bool, completion: (([Element])->Void)? = nil) {
            pthread_rwlock_wrlock(&lock)
            var elements = [Element]()
            while let index = array.firstIndex(where: predicate) {
                elements.append(array.remove(at: index))
            }
            completion?(elements)
            pthread_rwlock_unlock(&lock)
        }
    
        func removeAll(completion: (([Element])->Void)? = nil) {
            pthread_rwlock_wrlock(&lock)
            let elements = array
            array.removeAll()
            completion?(elements)
            pthread_rwlock_unlock(&lock)
        }
    }
    
    public extension ThreadSafeArray {
        subscript(index: Int)->Element? {
            get {
                pthread_rwlock_rdlock(&lock)
                var result: Element?
                guard self.array.startIndex..<self.array.endIndex ~= index else {
                    pthread_rwlock_unlock(&lock)
                    return nil
                }
                
                result = self.array[index]
                pthread_rwlock_unlock(&lock)
                return result
            }
            set {
                
                guard let newValue = newValue else {
                    return
                }
                if index < self.count {
                    pthread_rwlock_wrlock(&lock)
                    self.array[index] = newValue
                    pthread_rwlock_unlock(&lock)
                }
                
            }
        }
    }
    
    // MARK: - Equatable
    
    public extension ThreadSafeArray where Element: Equatable {
        func contains(_ element: Element)->Bool {
            pthread_rwlock_rdlock(&lock)
            let result = self.array.contains(element)
            pthread_rwlock_unlock(&lock)
            return result
        }
    }
    
    // MARK: - Infix operators
    
    public extension ThreadSafeArray {
        /// Adds a new element at the end of the array.
        ///
        /// - Parameters:
        ///   - left: The collection to append to.
        ///   - right: The element to append to the array.
        static func +=(left: inout ThreadSafeArray, right: Element) {
            left.append(right)
        }
    
        /// Adds new elements at the end of the array.
        ///
        /// - Parameters:
        ///   - left: The collection to append to.
        ///   - right: The elements to append to the array.
        static func +=(left: inout ThreadSafeArray, right: [Element]) {
            left.append(right)
        }
    }
    
    

    参考

    iOS多线程到底哪里不安全
    读写锁
    Swift线程安全详解-概念,三种锁,死锁,Atomic,synchronized

    相关文章

      网友评论

        本文标题:Swift 实现一个 线程安全的数组

        本文链接:https://www.haomeiwen.com/subject/etdevltx.html