我正在尝试运行一个串行通信示例,以便按照 http://playground.arduino.cc/Interfacing/Cocoa 中提供的代码将数据从 Arduino 发送到 Cocoa 应用程序(IOKit/ioctl 方法)。它有效,但一旦启动我就无法停止接收器线程。
我实现了一个开关按钮(开始/停止),它在启动时打开串行端口并启动接收器线程:
- (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的状态变化。
最佳答案
那么,startButton:
打开端口,生成一个线程以开始从中读取数据,然后立即关闭端口?结果不会很好。
startButton:
不应关闭端口。完成后将其留给读取线程执行,仅当您因其他原因(例如退出)需要关闭端口时才在主线程上执行此操作。
根据定义,全局变量在整个程序中都是可见的,这包括跨线程边界。如果 readThreadRunning
未设置为 FALSE
(假设 FALSE
尚未定义为外来的东西),那么您的读取线程的循环必须仍在运行。要么仍在读取数据,要么读取被阻塞(正在等待更多数据)。
请注意,read
无法知道是否会有更多数据。正如代码中的注释所述,它将阻塞,直到它有一些数据要返回或端口关闭为止。您应该想出一种方法来提前知道需要读取多少数据,并在读完那么多数据后停止,或者看看是否可以在所有内容都发送完毕后关闭另一端的端口,已收到。
关于cocoa - 如何关闭Cocoa后台线程中的串行通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14957463/