【问题标题】:Cancel thread with read() operation on serial port在串口上使用 read() 操作取消线程
【发布时间】:2011-08-27 22:52:37
【问题描述】:

在我的 Cocoa 项目中,我与连接到串行端口的设备进行通信。现在,我正在等待串行设备发送一些字节的特定消息。对于读取操作(以及收到所需消息后的反应),我创建了一个新线程。应用户请求,我希望能够取消线程。

正如 Apple 在 docs 中建议的那样,我在线程字典中添加了一个标志,定期检查该标志是否已设置,如果已设置,请调用 [NSThread exit]。这很好用。

现在,线程可能会卡住等待串行设备最终发送 12 字节消息。读取调用如下所示:

numBytes = read(fileDescriptor, buffer, 12);

一旦线程开始从设备读取,但没有数据进来,我可以设置标志告诉线程完成,但线程不会读取标志,除非它最终收到至少 12 字节的数据并继续处理。

有没有办法杀死当前在串行设备上执行读取操作的线程?

编辑澄清: 我不坚持为串行设备的 I/O 操作创建单独的线程。如果有一种方法可以封装操作,以便在用户按下取消按钮时我能够“杀死”它们,我会非常高兴。 我正在为桌面 Mac OS X 开发一个 Cocoa 应用程序,因此对移动设备及其功能没有限制。 如果没有要读取的字节,解决方法是让 read 函数立即返回。我该怎么做?

【问题讨论】:

    标签: objective-c c multithreading serial-port


    【解决方案1】:

    使用selectpoll 和超时来检测描述符何时可以读取。

    将超时设置为(比如说)半秒,并在循环中调用它,同时检查你的线程是否应该退出。

    异步线程取消几乎总是一个坏主意。尝试坚持使用事件驱动的接口(如果需要,还可以使用超时)。

    【讨论】:

    • 这是一个非常糟糕的方法。您永远不应该编写不断唤醒和轮询变量的应用程序。这会破坏电池寿命,听起来 OP 正在为移动设备编写此代码,这是一个大问题……您可以通过在 select/poll 中添加管道来消除超时/唤醒,从而获得相同的结果调用,并通过管道发送中止请求。
    • 我正在为桌面 Mac OS X 开发,所以没有移动设备限制。
    【解决方案2】:

    这正是pthread_cancel 接口的设计目的。您需要在 pthread_cleanup_pushpthread_cleanup_pop 中使用 read 包装块,以便在线程被取消时可以安全地清理,并在运行的其他代码中禁用取消(使用 pthread_setcancelstate)这个你不想被取消的线程。如果正确的清理涉及多个调用帧,这可能会很痛苦;它本质上迫使您在每个调用级别使用pthread_cleanup_push,并使用try/catch 样式的异常处理来构造您的线程代码,如C++ 或Java。

    另一种方法是为没有SA_RESTART 标志的其他未使用的信号(如SIGUSR1 或实时信号之一)安装信号处理程序,以便使用EINTR 中断系统调用。信号处理程序本身可以是完全无操作的;它的唯一目的是打断事情。然后您可以使用pthread_kill 中断特定线程中的read(或任何其他系统调用)。这样做的好处是您不必将代码切换为使用 C++/Java 类型的惯用语。您可以通过检查标志(指示线程是否被请求中止)来处理EINTR错误,如果未设置标志,则继续读取,或者返回导致调用者清理并最终pthread_exit的错误代码.

    如果您确实使用中断信号处理程序,请确保您所有可以返回 EINTR 的系统调用都包含在循环中,这些循环将在 EINTR 上重试(或检查中止标志并可选择重试)。否则事情可能会很糟糕。

    【讨论】:

    • 这是一个非常非常糟糕的方法。使用信号和EINTR 会产生不可避免的竞争条件,因为信号可能在线程进入 read() 之前传递。结果,读取不会被中断并且会永远阻塞,但只有在竞争条件触发时......使得该错误极难重现和修复。轮询几乎是无限可取的。 (也就是说,我同意最好的答案是在 select/poll 中添加一个管道。)
    • 在 OP 想要的交互式使用中,“永远阻塞”实际上是“阻塞直到用户再次按下取消按钮”。我同意这里有一个竞争条件,这可能很难解决。对于一般情况,我可以想到一个复杂的框架,其中包含一个重要的信号处理程序和信号处理程序中的 longjmps,可以满足要求而不会造成任何异步信号安全违规或其他 UB,但这可能不是 OP 想要的。 .
    猜你喜欢
    • 1970-01-01
    • 2013-12-18
    • 1970-01-01
    • 1970-01-01
    • 2011-11-15
    • 2011-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多