2013-11-14 67 views
1

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

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

我写得很直截了当。我刚刚使用unistd.h中声明的write函数。

阅读不起作用。每当我打电话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); 

什么我错在这里做什么?

+0

没有发送任何数据? –

回答

1

read()会阻止,如果没有什么可读的。苹果可能有自己的做法,但你可以使用select()来查看_fileDescriptor是否有任何可读的内容。谷歌围绕如何使用select的例子。

下面是关于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(). 
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这样做。