Golang串口通信中的多线程处理
Golang串口通信中的多线程处理 我正在尝试通过Arduino使用多线程从串行端口读取输入。我有两个线程从串行端口读取数据,它们都在读取相同的内容(忽略它们的函数名称)。以下是代码:
for scanner.Scan() {
log.Printf("%q\n", scanner.Text())
}
time.Sleep(time.Duration(1)*time.Second)
}
func readSecondLine(scanner *bufio.Scanner, port *serial.Port){
time.Sleep(time.Duration(1)*time.Second)
for scanner.Scan() {
log.Printf("%q\n", scanner.Text())
}
}
func main() {
usbRead := &serial.Config{Name: "COM5", Baud: 9600, ReadTimeout: 0}
port, err := serial.OpenPort(usbRead)
if err != nil {
log.Fatal(err)
}
scanner := bufio.NewScanner(port)
for true{
go readFirstLine(scanner, port)
go readSecondLine(scanner, port)
time.Sleep(time.Duration(2)*time.Second)
}
}
我期望的输出应该是这样的:
{"temperature":[26,26],"humidity":[54.2,54.2],"sensor":"DHT22"}
{"temperature":[23.46041,23.46041],"sensor":"LM35DZ"}
{"blink":["true","true"],"actuator":"arduinoLED"}
{"temperature":[26,26],"humidity":[54.2,54.2],"sensor":"DHT22"}
{"temperature":[23.46041,23.46041],"sensor":"LM35DZ"}
{"blink":["true","true"],"actuator":"arduinoLED"}
然而我在期望的输出之间得到了垃圾数据:
"{\"temperature\":[23.46041,23.46041,23.46041],\"sensor\":\"LM35DZ\"}"
"{\"blink\":[\"true\",\"true\",\"true\"],\"actuator\":\"arduinoLED\"}"
"mpeer\x00\x00re\"u:\x00\x00[]6\x00midhui\x00\x00[54\":.\x00\x00sen,\"s\x00\x00:or\"\"TH\x00"
{\"}\"\x00\x00ptemurrate\x003.4[26\x00\x00,\"s1]e\x00\x00\":\"orL\x00\x00Z\"}5D\r\x00\x00\x00"
我认为这些垃圾数据出现是因为我在Arduino没有输出任何内容时仍然在读取串行端口输入。有什么方法可以解决这个问题吗?谢谢。
更多关于Golang串口通信中的多线程处理的实战教程也可以访问 https://www.itying.com/category-94-b0.html
2 回复
我编写多线程应用程序来管理物联网设备和其他设备。有些设备发送数据较慢,但其他设备可以通过串行端口以1 Mb/s的速度发送数据,我必须同时管理它们。每个连接都有一个线程,没有丢失任何一个字节。你应该检查一下你的代码。
更多关于Golang串口通信中的多线程处理的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你的问题确实是由于多个goroutine同时从同一个bufio.Scanner读取数据导致的。bufio.Scanner不是并发安全的,当多个goroutine同时调用Scan()方法时会发生数据竞争和读取错乱。
以下是修正后的代码:
package main
import (
"bufio"
"log"
"time"
"github.com/tarm/serial"
)
func readFromSerial(scanner *bufio.Scanner, name string) {
for scanner.Scan() {
data := scanner.Text()
if data != "" {
log.Printf("[%s] %q\n", name, data)
}
}
}
func main() {
usbRead := &serial.Config{Name: "COM5", Baud: 9600, ReadTimeout: time.Millisecond * 100}
port, err := serial.OpenPort(usbRead)
if err != nil {
log.Fatal(err)
}
defer port.Close()
scanner := bufio.NewScanner(port)
// 只使用一个goroutine来读取串口数据
go readFromSerial(scanner, "Reader")
// 保持主程序运行
select {}
}
如果你确实需要多个消费者处理相同的数据,可以使用通道模式:
package main
import (
"bufio"
"log"
"time"
"github.com/tarm/serial"
)
func serialReader(scanner *bufio.Scanner, dataChan chan string) {
for scanner.Scan() {
data := scanner.Text()
if data != "" {
dataChan <- data
}
}
close(dataChan)
}
func dataProcessor(name string, dataChan chan string) {
for data := range dataChan {
log.Printf("[%s] %q\n", name, data)
}
}
func main() {
usbRead := &serial.Config{Name: "COM5", Baud: 9600, ReadTimeout: time.Millisecond * 100}
port, err := serial.OpenPort(usbRead)
if err != nil {
log.Fatal(err)
}
defer port.Close()
scanner := bufio.NewScanner(port)
dataChan := make(chan string, 100)
// 一个读取器,多个处理器
go serialReader(scanner, dataChan)
go dataProcessor("Processor1", dataChan)
go dataProcessor("Processor2", dataChan)
select {}
}
关键修改点:
- 移除了多个goroutine同时读取同一个scanner的设计
- 设置了合理的ReadTimeout(100毫秒)
- 使用通道来安全地在goroutine间传递数据
- 添加了空数据检查
这样应该能消除垃圾数据并得到你期望的输出格式。

