gpt4 book ai didi

cocoa - 如何检查 NSFileHandle 是否有可用数据?

转载 作者:行者123 更新时间:2023-12-03 16:22:31 25 4
gpt4 key购买 nike

我正在使用 NSTask,配置了 3 个 NSPipe,并且想要读取 standardOutput 和 standardError。我在 while 内执行此操作 - 第一个用于标准输出,第二个用于标准错误。我不能使用 readInBackgroundAndNotify 和 waitForDataInBackgroundAndNotify,因为我的代码已经在单独的线程中运行,并且我不想在那里运行 NSRunLoop 并分离新的后台线程...但是读取两者 - stdout 和 stderr 会导致在没有可用数据时挂起数据存在于这些 channel 之一。

所以我使用这段代码:

@implementation NSFileHandle (isReadableAddon)

- (BOOL)isReadable
{
int fd = [self fileDescriptor];
fd_set fdset;
struct timeval tmout = { 0, 0 }; // return immediately
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
if (select(fd + 1, &fdset, NULL, NULL, &tmout) <= 0)
return NO;
return FD_ISSET(fd, &fdset);
}

@end

但是,当 isReadable 返回 YES 并且我调用 [fileHandle availableData] 时,我的线程仍然阻塞。为什么?我期望当 isReadable 返回 YES 时调用 availableData 方法而不阻塞。

最佳答案

我也更喜欢使用 select 但如果您想使用非阻塞阅读,这里有一个适合我的要点。

swift 4

var flags = fcntl(fileDescriptor, F_GETFL)
_ = fcntl(fileDescriptor, F_SETFL, flags | O_NONBLOCK)

public var nonBlockingAvailableData: Data? {
return self.__readDataOfLength(Int.max, untilEOF: false)
}

internal func __readDataOfLength(_ length: Int, untilEOF: Bool) -> Data? {
let _closed: Bool = false

let _fd = self.fileDescriptor
var statbuf = stat()
var dynamicBuffer: UnsafeMutableRawPointer? = nil
var total = 0
if _closed || fstat(_fd, &statbuf) < 0 {
fatalError("Unable to read file")
}
if statbuf.st_mode & S_IFMT != S_IFREG {
/* We get here on sockets, character special files, FIFOs ... */
var currentAllocationSize: size_t = 1024 * 8
dynamicBuffer = malloc(currentAllocationSize)

var remaining = length
while remaining > 0 {

let amountToRead = min(1024 * 8, remaining)
// Make sure there is always at least amountToRead bytes available in the buffer.
if (currentAllocationSize - total) < amountToRead {
currentAllocationSize *= 2

dynamicBuffer = reallocf(dynamicBuffer!, currentAllocationSize)
if dynamicBuffer == nil {
fatalError("unable to allocate backing buffer")
}
}

let amtRead = read(_fd, dynamicBuffer!.advanced(by: total), amountToRead)
//Needs better errorhandling, check ERRNO?
if amtRead == -1 {
return nil
}

if 0 > amtRead {
free(dynamicBuffer)
fatalError("read failure")
}
if 0 == amtRead {
break // EOF
}

total += amtRead
remaining -= amtRead

if total == length || untilEOF == false {
break // We read everything the client asked for.
}
}
}

if length == Int.max && total > 0 {
dynamicBuffer = reallocf(dynamicBuffer!, total)
}

if total == 0 {
free(dynamicBuffer)
}
else if total > 0 {
let bytePtr = dynamicBuffer!.bindMemory(to: UInt8.self, capacity: total)
return Data(bytesNoCopy: bytePtr, count: total, deallocator: .free)
}
else {
assertionFailure("The total number of read bytes must not be negative")
free(dynamicBuffer)
}

return Data()
}

参见 Linux select手册页:

Under Linux, select() may report a socket file descriptor as "ready for reading", while nevertheless a subsequent read blocks. This could for example happen when data has arrived but upon examination has wrong checksum and is discarded. There may be other circumstances in which a file descriptor is spuriously reported as ready. Thus it may be safer to use O_NONBLOCK on sockets that should not block.

关于cocoa - 如何检查 NSFileHandle 是否有可用数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7505777/

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