You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift实现线程安全Deque遇问题:size()异常及实现方案咨询

线程安全Deque实现的问题分析与修正

原实现的核心问题

  1. 异步调用导致返回值未更新:你用mQueue.async(flags: .barrier)执行闭包,这是异步操作——调用线程不会等待闭包执行完成,直接返回初始值(比如size()里的ret初始为0,闭包还没赋值就返回了),这就是size()始终返回0的根本原因。
  2. 线程不安全的前置判断:pushBack里先在无锁状态下读取mJobFifo.count,再异步加锁写入,这个判断和写入不是原子操作,多线程下可能出现多个线程同时判断count < maxSize,然后都执行append,导致队列超出最大容量。
  3. popFirst无法正确返回元素:同样因为async异步特性,返回的ret还是初始的nil,闭包里的赋值逻辑还没执行就返回了结果。

正确的实现方式(基于GCD并发队列)

GCD并发队列实现线程安全容器的标准姿势是:

  • 读操作:用同步(sync)普通任务,支持多个读请求并发执行,不阻塞彼此。
  • 写/修改操作:用同步(sync)屏障任务,确保执行时队列内无其他任务,独占访问资源。

修改后的完整代码:

import Foundation
import DequeModule

enum QueueError: Error {
    case full
}

class OcrJob {
    static var lastJobId: Int = 0
    let jobId: Int
    
    init() {
        jobId = OcrJob.lastJobId
        OcrJob.lastJobId += 1
    }
}

class OcrJobQueue {
    private let maxSize: UInt
    private let queue = DispatchQueue(label: "JobQueue", attributes: .concurrent)
    private var jobFifo: Deque<OcrJob> = []
    
    init(max: UInt) {
        self.maxSize = max
    }
    
    public func size() -> Int {
        // 读操作:同步执行,无需屏障,支持并发读
        return queue.sync {
            let count = jobFifo.count
            print("internal size: \(count)")
            return count
        }
    }
    
    public func pushBack(job: OcrJob) throws {
        // 写操作:同步屏障任务,确保判断与写入的原子性
        try queue.sync(flags: .barrier) {
            guard jobFifo.count < maxSize else {
                print("pushBack - curSize: \(jobFifo.count), maxSize \(maxSize)")
                throw QueueError.full
            }
            jobFifo.append(job)
            print("pushBack: \(jobFifo.count) jobs in queue")
        }
    }
    
    public func popFirst() -> OcrJob? {
        // 修改操作:同步屏障任务,确保弹出操作的原子性
        return queue.sync(flags: .barrier) {
            let job = jobFifo.popFirst()
            print("popFirst: \(jobFifo.count) jobs in queue")
            return job
        }
    }
}

关键修改点说明

  • 将所有async替换为sync:确保调用线程等待闭包执行完成,拿到正确的返回值。
  • 把pushBack的容量检查移到屏障闭包内:保证判断与写入是原子操作,避免多线程下的容量溢出。
  • 补全QueueError定义:原代码未声明该枚举,会导致编译报错。
  • 优化变量命名:符合Swift代码风格,提升可读性。

是否为最优方案?

基于GCD并发队列的实现是macOS平台下线程安全容器的轻量高效方案,完全适配你的服务器线程池任务场景。如果后续需要等待队列非空/非满的阻塞逻辑,可以结合DispatchSemaphore扩展,但基础线程安全Deque用该方案足够。

内容的提问来源于stack exchange,提问作者Danny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 16:31:10