swift實現線程安全的棧和隊列

實現一個線程安全的棧

這裏使用數組來存儲棧的數據。不足之處在於本例中的Stack能夠無限擴容,更好的是初始化時候指定一個最大容量,防止不斷擴容申請內存致使內存不夠的問題。這裏的線程安全使用一個串行隊列來保證,實際上也能夠經過加鎖或者信號量甚至自旋鎖來解決。node

struct Stack<Element> {
    
    private var items: [Element]
    
    private var queue = DispatchQueue(label: "StackOperationQueue")
    
    public init(capacity: Int = 10) {
        items = [Element]()
        items.reserveCapacity(capacity)
    }
    
    mutating public func push(item: Element) {
        queue.sync {
            items.append(item)
        }
    }
    
    mutating public func pop() -> Element? {
        var item: Element?
        queue.sync {
            item = items.removeLast()
        }
        return item
    }
}

實現一個線程安全的隊列

// 存儲數據的雙向鏈表節點
class DoubleLinkNode<Element> {
    var previous: DoubleLinkNode?
    var next: DoubleLinkNode?
    let val: Element?
    init(val: Element?) {
        self.val = val
    }
    //聲明==運算符,便於判斷兩個節點是否相等
    static func ==(left: DoubleLinkNode<Element>, right: DoubleLinkNode<Element>) -> Bool {
        //最準確的作法是判斷內存地址是否相同
        let leftPointValue = Unmanaged<AnyObject>.passUnretained(left).toOpaque()
        let rightPointValue = Unmanaged<AnyObject>.passUnretained(right).toOpaque()
        return leftPointValue == rightPointValue
    }
}

/*
 1.使用雙向鏈表實現隊列結構,聲明空的head/last哨兵節點簡化雙向鏈表操做;
 2.使用串行隊列保證線程安全,實際上也能夠經過加鎖的方式實現線程安全;
 3.對於生產者-消費者模型,這裏可使用semaphore來實現,當隊列爲空的時候,讓線程休眠,當有元素入隊的時候喚醒一個線程繼續執行任務。
 */
struct Queue<Element> {
    //聲明串行隊列,將操做放在串行隊列中,保證線程安全
    private var queue = DispatchQueue(label: "QueueOperationQueue")
    
    let firstNode: DoubleLinkNode<Element>
    let lastNode: DoubleLinkNode<Element>
    
    public init(capacity: Int = 20) {
        firstNode = DoubleLinkNode(val: nil)
        lastNode = DoubleLinkNode(val: nil)
        firstNode.next = lastNode
        lastNode.previous = firstNode
    }
    
    /// 入隊操做
    mutating public func enqueue(item: Element) {
        queue.sync {
            let node = DoubleLinkNode<Element>(val: item)
            let tmp = firstNode.next
            firstNode.next = node
            node.previous = firstNode
            node.next = tmp
            tmp?.previous = node
        }
    }
    
    /// 出隊操做
    mutating public func dequeue() -> Element? {
        guard let previous = lastNode.previous, !(firstNode == previous) else { return nil }
        var node: DoubleLinkNode<Element>? = nil
        queue.sync {
            node = lastNode.previous
            node?.next = nil
            node?.previous = nil
            let tmp = node?.previous
            lastNode.previous = tmp
            tmp?.next = lastNode
        }
        return node?.val
    }
}
相關文章
相關標籤/搜索