zoukankan      html  css  js  c++  java
  • swift实现线程安全的栈和队列

    实现一个线程安全的栈

    这里使用数组来存储栈的数据。不足之处在于本例中的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
        }
    }
    
  • 相关阅读:
    Json解析
    Nopcommerce 使用Task时dbcontext关闭问题
    Webview离线功能(优先cache缓存+cache缓存管理)
    Android按钮单击事件的四种常用写法
    xUtils 源码解析
    返回键的复写onBackPressed()介绍
    GBK、GB2312和UTF-8编码区分
    Android 动画之RotateAnimation应用详解
    Android getWidth和getMeasuredWidth的区别
    WebView三个方法区别(解决乱码问题)
  • 原文地址:https://www.cnblogs.com/dev-walden/p/11396048.html
Copyright © 2011-2022 走看看