4

從串行端口讀取時,使用Grand Central調度源事件時遇到問題。無法使用GCD調度源讀取串行端口文件描述符

我使用dispatch_source_create和DISPATCH_SOURCE_TYPE_READ,這樣當從與串口相關聯的fileDescriptor中讀取數據時,OS將運行我的代碼塊。這裏是我的代碼

- (void) receiveThread 
{ 
    globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, 
                 [self fileDescriptor], 
                 0, 
                 globalQueue); 

    dispatch_source_set_event_handler(readSource, ^{ 
     char buffer[512]; 
     NSString *bar; 
     ssize_t numBytes; 
     int expected; 

     expected = dispatch_source_get_data(readSource); 
     printf("expected:%d\n",expected); 

     do { 
      numBytes = read([self fileDescriptor], buffer, 512); 
      buffer[numBytes] = '\x000'; //make sure that the string is terminated. 
      printf("bytes:%ld\n",numBytes); 
      if (numBytes != -1) 
      { 
       bar = [NSString stringWithCString:&buffer]; 
       //printf("bytes:%ld\n",numBytes); 
       NSLog(@"String:%@\n",bar); 
       [[NSNotificationCenter defaultCenter] postNotificationName:EISerialTextDidArrive object:bar]; 
      } 
     } while (numBytes > 0); 

    }); 
    dispatch_resume(readSource); 
} 

當程序運行時該塊被稱爲第一次發送串行數據到端口。然後,我在控制檯中收到消息

[Switching to process 11969 thread 0x6603] 

當更多字符發送到串行端口時,不會調用該代碼塊。我仍然可以從串口發送字符,並且我可以確認字符正在發送,但塊不會再次運行。

從Web上的文檔和示例中,我期望只要串行緩衝區中有字符就可以重複調用該塊。

+0

看起來好像串行端口不能用這種方式與GCD一起工作。我曾嘗試使用MAAsyncIO庫,其結果與上面的嘗試類似。我可以確認串口使用select()函數調用。我一直無法讓他們使用kqueue(),儘管我懷疑這是由我的代碼中的問題引起的。 – 2011-03-23 23:21:44

回答

3

@KazukiSakamoto是正確地指出,文件描述符上應該有O_NONBLOCK集。我發現了其他一些可能導致你困擾的問題:當你僅僅使用buffer時,你正在使用&buffer。此外,你有一個512字節的緩衝區,然後你最多可以讀取512個字節,並將下一個設置爲0(空終止)。如果您確實讀取了512字節,則會導致緩衝區溢出。此外,它似乎readSource是一個iVar,並且您在該塊中引用self。這可能會產生一個保留週期,應該避免。無論如何,我寫了一個最小的小應用程序,然後將我的串口的引腳2和3短接,這樣任何寫出來的東西都會被回顯,然後在我的應用程序中連接一個按鈕來發送一些數據。像魅力一樣工作!這裏是代碼:

@implementation SOAppDelegate 
{ 
    int fd; 
    dispatch_source_t readSrc; 
} 

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification 
{ 
    fd = open("/dev/mySerialPort", O_RDWR | O_NONBLOCK); 
    __block dispatch_source_t blockReadSrc = readSrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_main_queue()); 

    dispatch_source_set_event_handler(readSrc, ^{ 
     NSLog(@"expected: %lu\n", dispatch_source_get_data(blockReadSrc)); 
     ssize_t numBytes; 
     do { 
      char buffer[513]; 
      numBytes = read((int)dispatch_source_get_handle(blockReadSrc), buffer, 512); 
      buffer[numBytes] = '\x000'; //make sure that the string is terminated. 
      NSLog(@"numBytes: %ld\n",numBytes); 
      if (numBytes != -1) 
      { 
       NSLog(@"String:%@\n", [NSString stringWithUTF8String: buffer]); 
      } 
     } while (numBytes > 0); 
    }); 

    dispatch_resume(readSrc); 
} 

- (IBAction)sendData: (id)sender 
{ 
    write(fd, "foobar", 6); 
} 

- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender 
{ 
    if (fd > 0) close(fd); fd = 0; 
    if (readSrc) dispatch_release(readSrc); readSrc = nil; 
    return NSTerminateNow; 
} 

@end 
+0

工程就像一個魅力。 – 2017-09-07 08:31:15

1

AFAIK,[self fileDescriptor]應該是非阻塞的。你確定嗎?

fcntl([self fileDescriptor], F_SETFL, O_NONBLOCK); 
相關問題