2

我正在尝试运行一个串行通信示例,以便按照http://playground.arduino.cc/Interfacing/Cocoa(IOKit/ioctl 方法)中提供的代码将数据从 Arduino 发送到 Cocoa 应用程序。它可以工作,但是一旦启动,我就无法停止接收器线程。

我已经实现了一个开关按钮( Start/Stop ),它在开始时打开串行端口并启动接收器线程:

- (IBAction) startButton: (NSButton *) btn {
(…)
error = [self openSerialPort: [SelectPort titleOfSelectedItem] baud:[Baud intValue]];
(…)
[self refreshSerialList:[SelectPort titleOfSelectedItem]];
[self performSelectorInBackground:@selector(incomingTextUpdateThread:) withObject:[NSThread currentThread]];
(…)
}

线程代码实际上与示例中的相同,除了我包含了从接收的缓冲区重建串行数据包并将其保存到 SQLite 数据库的代码:

- (void)incomingTextUpdateThread: (NSThread *) parentThread {

// mark that the thread is running
readThreadRunning = TRUE;

const int BUFFER_SIZE = 100;
char byte_buffer[BUFFER_SIZE];  // buffer for holding incoming data
int numBytes=0;                 // number of bytes read during read

(…)

// assign a high priority to this thread
[NSThread setThreadPriority:1.0];

// this will loop until the serial port closes
while(TRUE) {
    // read() blocks until some data is available or the port is closed
    numBytes = (int) read(serialFileDescriptor, byte_buffer, BUFFER_SIZE); // read up to the size of the buffer
    if(numBytes>0) {
        // format serial data into packets, but first append at start the end of last read
        buffer = [[NSMutableString alloc] initWithBytes:byte_buffer length:numBytes encoding:NSASCIIStringEncoding];
        if (status == 1 && [ipacket length] != 0) {
           [buffer insertString:ipacket atIndex:0];
           numBytes = (int) [buffer length];
        }
        ipacket = [self processSerialData:buffer length:numBytes];   // Recompose data and save to database.
    } else {
        break; // Stop the thread if there is an error
    }
}

// make sure the serial port is closed
if (serialFileDescriptor != -1) {
    close(serialFileDescriptor);
    serialFileDescriptor = -1;
}

// mark that the thread has quit
readThreadRunning = FALSE;

}

我尝试使用此代码关闭主线程中的端口,这也是 startButton 选择器的一部分,遵循提供的示例:

if (serialFileDescriptor != -1) {
    [self appendToIncomingText:@"Trying to close the serial port...\n"];
    close(serialFileDescriptor);
    serialFileDescriptor = -1;

    // Revisar... crec que el thread no s'adona que s'ha tancat el file descriptor...
    // wait for the reading thread to die
    while(readThreadRunning);
    // re-opening the same port REALLY fast will fail spectacularly... better to sleep a sec
    sleep(0.5);

    //[btn setTitle:@"Start"];
    [Start setTitle:@"Start"];
}

但似乎接收者线程不知道全局变量serialFileDescriptor中的状态变化。

4

1 回答 1

0

So, startButton: opens the port, spawns off a thread to start reading from it, and then immediately closes the port? That's not going to turn out well.

startButton: should not close the port. Leave that for the reading thread to do when it's done, and do it on the main thread only when you need to close the port for some other reason (e.g., quitting).

Global variables are, by definition, visible throughout the program, and this includes across thread boundaries. If readThreadRunning is not getting set to FALSE (which assumes that FALSE hasn't been defined to something exotic), then your read thread's loop must still be running. Either it is still reading data, or read is blocked (it is waiting for more data).

Note that read has no way to know whether there will be more data. As your comment in the code says, it will block until either it has some data to return or the port gets closed. You should either work out a way to know ahead of time how much data you'll need to read, and stop when you've read that much, or see if you can close the port at the opposite end when everything has been sent and received.

于 2013-02-19T20:51:32.787 回答