gpt4 book ai didi

ios - 带 GCD 的异步 NSStream I/O

转载 作者:行者123 更新时间:2023-11-29 00:19:09 26 4
gpt4 key购买 nike

我正在使用从中接收数据的外部设备。我想在一个线程中异步处理它的数据读/写队列。

我已经得到它的大部分工作:有一个简单地管理两个流的类,使用 NSStreamDelegate 响应传入的数据,以及响应 NSStreamEventHasSpaceAvailable 发送等待的数据在之前发送失败后在缓冲区中。

这个类,我们称它为 SerialIOStream,不知道线程或 GCD 队列。相反,它的用户,让我们称它为 DeviceCommunicator,使用一个 GCD 队列,它在其中初始化 SerialIOStream 类(它反过来创建并打开流,将它们安排在当前运行循环):

ioQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_async(ioQueue, ^{
ioStreams = [[SerialIOStream alloc] initWithPath:[@"/dev/tty.mydevice"]];
[[NSRunLoop currentRunLoop] run];
});

这样,SerialIOStreamstream:handleEvent: 方法显然会在该 GCD 队列中运行。

但是,这会导致一些问题。我相信我遇到了并发问题,直到崩溃,主要是在将未决数据提供给输出流时。代码中有一个关键部分,我将缓冲的输出数据传递到流,然后查看实际接受到流中的数据量,然后从缓冲区中删除该部分:

NSInteger n = self.dataToWrite.length;
if (n > 0 && stream.hasSpaceAvailable) {
NSInteger bytesWritten = [stream write:self.dataToWrite.bytes maxLength:n];
if (bytesWritten > 0) {
[self.dataToWrite replaceBytesInRange:NSMakeRange(0, bytesWritten) withBytes:NULL length:0];
}
}

上面的代码可以从两个地方调用:

  1. 来自用户(DeviceCommunicator)
  2. 从本地 stream:handleEvent: 方法,在被告知输出流中有空间后。

它们可能(好吧,肯定是)在单独的线程中运行,因此我需要确保它们不会同时运行此代码。

我想在发送新数据时可以通过在 DeviceCommunicator 中使用以下代码来解决这个问题:

dispatch_async (ioQueue, ^{
[ioStreams writeData:data];
});

(writeData 将数据添加到 dataToWrite,请参见上文,然后运行上述代码将其发送到流。)

但是,这不起作用,显然是因为 ioQueue 是一个并发队列,它可能决定使用任何可用的线程,因此当 writeData 调用时会导致竞争条件>DeviceCommunicator,同时还可以在单​​独的线程上从 stream:handleEvent: 调用它。

所以,我想我将对线程的期望(我对此比较熟悉)混入了我对 GCD 队列的明显误解中。

如何正确解决这个问题?

我可以添加一个 NSLock,用它保护 writeData 方法,我相信这可以解决该地方的问题。但我不太确定 GCD 应该如何使用 - 我的印象是这是一个障碍。

我应该创建一个单独的类,使用它自己的串行队列来访问和修改 dataToWrite 缓冲区吗?

我仍在尝试掌握与此相关的模式。不知何故,它看起来像一个经典的生产者/消费者模式,但在两个层面上,而我做得不对。

最佳答案

长话短说:不要过河! (哈哈)

NSStream 是一个基于 RunLoop 的抽象(也就是说,它打算在 NSRunLoop 上协作完成其工作,这是一种早于 GCD 的方法)。如果您主要使用 GCD 来支持其余代码中的并发,那么 NSStream 不是执行 I/O 的理想选择。 GCD 提供了自己的 API 来管理 I/O。请参阅 this page 上标题为“管理调度 I/O”的部分.

如果你想继续使用 NSStream,你可以通过在主线程 RunLoop 上调度你的 NSStream 来实现,或者你可以启动一个专用的后台线程,将它安排在那边的 RunLoop 上,然后在该线程和 GCD 队列之间来回编码数据。 (...但不要那样做;硬着头皮使用 dispatch_io。)

关于ios - 带 GCD 的异步 NSStream I/O,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44465981/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com