Swift 4调用C++桥接函数:如何终止执行中的线程?
如何终止运行无限循环C++ API的DispatchWorkItem?
我太懂你这个痛点了——用DispatchWorkItem在后台跑带无限循环的C函数,点停止按钮调用cancel()根本不管用,线程该跑还是跑。问题出在DispatchWorkItem的cancel()根本不是强制终止线程的手段,它只是给这个任务打个“已取消”的标记而已,你的C循环完全没在看这个标记,当然停不下来。
下面给你一套可行的解决思路,分两步走:
第一步:给C++ API加“可终止”的逻辑
既然是C++的无限循环,就得让它自己能感知到“该停了”。我们可以加一个线程安全的终止信号,让循环每次迭代都检查这个信号:
// C++ 侧代码(需要暴露给Swift调用) #include <atomic> // 用原子变量保证多线程读写安全,避免竞态条件 std::atomic<bool> g_shouldStopProcessing(false); void foo() { g_shouldStopProcessing = false; // 启动前重置状态 while (!g_shouldStopProcessing) { // 你的等待数据、填充数组的逻辑 // ... // 如果有阻塞式操作(比如sleep、等待IO),尽量用带超时的版本 // 比如把 sleep(1000) 改成 for (int i=0; i<10 && !g_shouldStopProcessing; i++) sleep(100); // 这样每100ms检查一次终止信号 } } // 暴露给Swift的停止函数 void stopFoo() { g_shouldStopProcessing = true; }
这里用std::atomic<bool>是关键,它能确保Swift线程和C++工作线程对这个变量的读写是原子性的,不会出现半写半读的诡异问题。
第二步:调整Swift侧的停止逻辑
别再只依赖workItem.cancel()了,直接调用我们刚加的C++停止函数,让循环自己退出:
var workItem: DispatchWorkItem? @IBAction func startButtonTapped(_ sender: UIButton) { workItem = DispatchWorkItem { foo() // 调用C++的处理函数 } DispatchQueue.global(qos: .background).async(execute: workItem!) } @IBAction func stopButtonTapped(_ sender: UIButton) { // 先给C++发停止信号,让循环自己结束 stopFoo() // 再取消workItem(其实循环结束后任务自然完成,这一步主要是标记状态) workItem?.cancel() workItem = nil // 释放资源,避免野指针 }
为啥原来的cancel()没用?
再给你补个知识点:DispatchWorkItem的cancel()只有两种场景有用:
- 任务还没被调度执行的时候,会直接取消调度;
- 任务已经在执行,但你在Swift代码里主动检查
workItem?.isCancelled的状态。
但你的逻辑是调用C的函数,Swift代码根本没机会在循环里检查取消状态,所以cancel()相当于完全没起作用。必须让执行的代码(也就是C的循环)自己支持终止逻辑才行。
额外提醒
如果你的C++函数里有阻塞式等待(比如一直卡着等数据到来,没有循环迭代),那得把这个阻塞操作改成可中断的。比如:
- 用带超时的等待API,每次超时后检查终止信号;
- 用信号量/条件变量来唤醒等待的线程,配合终止信号一起使用。
这样才能保证点击停止后,线程能及时退出,不会一直卡在阻塞状态。
内容的提问来源于stack exchange,提问作者AlexBerd
相关产品推荐
相关产品推荐

