码迷,mamicode.com
首页 > 编程语言 > 详细

swift实现线程安全的栈和队列

时间:2019-08-22 18:29:28      阅读:90      评论:0      收藏:0      [点我收藏+]

标签:vat   lse   tmp   导致   内存   pen   isp   init   问题   

实现一个线程安全的栈

这里使用数组来存储栈的数据。不足之处在于本例中的Stack可以无限扩容,更好的是初始化时候指定一个最大容量,防止不断扩容申请内存导致内存不够的问题。这里的线程安全使用一个串行队列来保证,实际上也可以通过加锁或者信号量甚至自旋锁来解决。

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

swift实现线程安全的栈和队列

标签:vat   lse   tmp   导致   内存   pen   isp   init   问题   

原文地址:https://www.cnblogs.com/dev-walden/p/11396048.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!