2013-11-14 63 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這樣做。