OSX串行读取冻结/挂起

时间:2013-11-14 15:49:10

标签: objective-c c macos select serial-port

我正在Objective-C中编写一个串行通信包装器类。要列出所有可用的串行调制解调器并设置连接,我使用的代码与this example project by Apple中使用的代码几乎相同。

我可以读写苹果做的方式。但我想在第二个线程上实现一个循环,如果NSString *writeString长0则写入流,如果字节可用,则写入后读取。

我的写作非常直接。我刚刚使用了write中声明的unistd.h函数。

阅读不起作用。每当我调用read()时,函数都会挂起,我的循环不会继续。

以下是我的循环中使用的代码:

- (void)runInCOMLoop {
    do {
        // write
    } while (bytesWritten < strlen([_writeString UTF8String]));

    NSMutableString *readString = [NSMutableString string];
    ssize_t bytesRead = 0;
    ssize_t readB = 0;
    char buffer[256];

    do {
        readB = read(_fileDescriptor, &buffer, sizeof(buffer));
//              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this function hangs
        bytesRead += readB;

        if (readB == -1 {
            // error
        }
        else if (readB > 0) {
            if(buffer[bytesRead - 1] == '\r' ]] buffer[bytesRead - 1] == '\n') {
                break;
            }

            [readString appendString:[NSString stringWithUTF8String:buffer]];
        }
    } while (readB > 0);

我在这里做错了什么?

2 个答案:

答案 0 :(得分:1)

如果没有什么可读的话,

read()会阻止。 Apple可能有自己的做法,但您可以使用select()查看_fileDescriptor上是否有任何内容可供阅读。谷歌周围有关如何使用选择的例子。

这是StackOverflow上的一个链接:

Can someone give me an example of how select() is alerted to an fd becoming "ready"

选择人的摘录属于:

     To effect a poll, the timeout argument should be
     non-nil, pointing to a zero-valued timeval structure.  Timeout is not
     changed by select(), and may be reused on subsequent calls, however it is
     good style to re-initialize it before each invocation of select().

答案 1 :(得分:0)

您可以使用O_NONBLOCK在文件描述符上设置非阻塞标记(fcntl()),以防止read()等待数据,但如果您这样做,则必须持续民意调查寻找数据,这从CPU使用的角度来看显然是不好的。正如Charlie Burns的回答所解释的那样,最好的解决方案是使用select(),这将允许您的程序有效地等待,直到在端口的文件描述符上读取一些数据。以下是我自己的Objective-C串口类ORSSerialPort(稍加修改)的一些示例代码:

fd_set localReadFDSet;
FD_ZERO(&localReadFDSet);
FD_SET(self.fileDescriptor, &localReadFDSet);

timeout.tv_sec = 0; 
timeout.tv_usec = 100000; // Check to see if port closed every 100ms

result = select(localPortFD+1, &localReadFDSet, NULL, NULL, &timeout);
if (!self.isOpen) break; // Port closed while select call was waiting
if (result < 0) {
    // Handle error
}

if (result == 0 || !FD_ISSET(localPortFD, &localReadFDSet)) continue;

// Data is available
char buf[1024];
long lengthRead = read(localPortFD, buf, sizeof(buf));
NSData *readData = nil;
if (lengthRead>0) readData = [NSData dataWithBytes:buf length:lengthRead];

请注意select()表示返回时数据可用。因此,如果没有可用数据,您的计划将暂停在select()来电。该程序挂起,这就是它应该如何工作。如果在select()等待时需要执行其他操作,则应将select()调用放在与您需要执行的其他工作不同的队列/线程上。 ORSSerialPort这样做。