ThreadSanitizer下Task.sleep触发数据竞争告警是否为误报
启用Thread Sanitizer运行单元测试时
Task.sleep触发Data Race告警 问题现象
开启Thread Sanitizer运行单元测试时,执行以下语句会出现Data Race警告:
try? await Task.sleep(nanoseconds: 10_000_000)
更新说明
- 仅使用Swift Combine与Swift Concurrency相关API即可稳定复现该数据竞争警告,已确认自身业务代码并非问题诱因,原有业务相关代码已移除。
- 复现前置要求:复现前需在测试Scheme的「Diagnostics」配置项中开启Thread Sanitizer。测试逻辑为启动任务后等待10秒触发超时取消,循环中每0.01秒调用一次上述
Task.sleep语句即可触发数据竞争,可独立运行的XCTest复现代码如下:
import XCTest import Combine extension Publisher { func asyncMap<T>( _ transform: @escaping @Sendable (Output) async -> T ) -> Publishers.FlatMap<Future<T, Never>, Self> where Output: Sendable { flatMap { value in Future { promise in Task { let output = await transform(value) promise(.success(output)) } } } } } class ThreadSafetyTests: XCTestCase { func testExample() throws { let expectCompletion = expectation(description: "completion") expectCompletion.isInverted = true let cancellable = ["a", "b", "b"].publisher .asyncMap { (string: String) -> String in while !Task.isCancelled { try? await Task.sleep(nanoseconds: 10_000_000) // 0.01 second } return string.uppercased() } .sink { completion in expectCompletion.fulfill() // it should never fullfill! } receiveValue: { string in } wait(for: [expectCompletion], timeout: 10) cancellable.cancel() } }
Thread Sanitizer告警详情
控制台输出的ThreadSanitizer详细告警日志如下:
WARNING: ThreadSanitizer: data race (pid=40024) Read of size 8 at 0x7b6400040d30 by thread T3: #0 (1) await resume partial function for closure #1 in ThreadSafetyTests.testExample() ThreadSafetyTests.swift:29 (OakTests:x86_64+0x6846a) #1 swift::runJobInEstablishedExecutorContext(swift::Job*) <null>:2 (libswift_Concurrency.dylib:x86_64+0x2be53) Previous write of size 8 at 0x7b6400040d30 by thread T1: #0 (1) await resume partial function for closure #1 in ThreadSafetyTests.testExample() ThreadSafetyTests.swift:29 (OakTests:x86_64+0x6857e) #1 swift::runJobInEstablishedExecutorContext(swift::Job*) <null>:2 (libswift_Concurrency.dylib:x86_64+0x2be53) Location is heap block of size 1032 at 0x7b6400040b00 allocated by thread T6: #0 malloc <null>:3 (libclang_rt.tsan_osx_dynamic.dylib:x86_64h+0x532ec) #1 swift::StackAllocator<1000ul, &(swift::TaskAllocatorSlabMetadata)>::getSlabForAllocation(unsigned long) <null>:2 (libswift_Concurrency.dylib:x86_64+0x30c9a) #2 swift::runJobInEstablishedExecutorContext(swift::Job*) <null>:2 (libswift_Concurrency.dylib:x86_64+0x2be53) Thread T3 (tid=4063077, running) is a GCD worker thread Thread T1 (tid=4063076, running) is a GCD worker thread Thread T6 (tid=4063081, running) is a GCD worker thread SUMMARY: ThreadSanitizer: data race ThreadSafetyTests.swift:29 in (1) await resume partial function for closure #1 in ThreadSafetyTests.testExample()
当前判断
目前排查后认为业务代码侧无对应修复方案,怀疑该告警为ThreadSanitizer误报,欢迎提供相关参考意见。后续更新内容已删除。
内容的提问来源于stack exchange,提问作者CouchDeveloper
相关产品推荐
相关产品推荐

