固定缓冲区大小:在这种情况下,你将缓冲区大小固定为4096字节。如果你的数据量可能超过这个限制,可能需要反复调用读取操作以确保读取完整的数据。
局部变量初始化:在C++中,局部变量如果不是内置类型(如int、char等),编译器会自动调用其默认构造函数进行初始化。对于内置类型,如果不显式初始化,它们的值是未定义的,可能包含任何内容。在你的代码中,buffer是一个字符数组,不需要显式初始化,因为你马上就会用::read函数把数据填充进去。
错误处理:::read函数可能会返回负值,以指示读取失败。你应该检查bytes_read是否为负值,并相应地处理错误情况。
字符串构造:如果::read返回负值,那么std::string(buffer, bytes_read)中的bytes_read将是负值,这会导致未定义行为。你需要确保bytes_read是非负的。
综合这些考虑,可以改进你的代码如下:
cpp
#include
#include
#include
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include
class ThreadSafeSerialPort {
public:
ThreadSafeSerialPort(const std::string& port_name, int baud_rate) {
fd_ = open(port_name.c_str(), O_RDWR | O_NOCTTY | O_SYNC);
if (fd_ < 0) {
throw std::runtime_error("Failed to open serial port");
}
struct termios tty;
memset(&tty, 0, sizeof tty);
if (tcgetattr(fd_, &tty) != 0) {
close(fd_);
throw std::runtime_error("Failed to get terminal attributes");
}
cfsetospeed(&tty, baud_rate);
cfsetispeed(&tty, baud_rate);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo, no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 1; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls, enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr(fd_, TCSANOW, &tty) != 0) {
close(fd_);
throw std::runtime_error("Failed to set terminal attributes");
}
}
~ThreadSafeSerialPort() {
close(fd_);
}
void write(const std::string& data) {
std::lock_guard<std::mutex> guard(mutex_);
::write(fd_, data.c_str(), data.size());
}
std::string read() {
std::lock_guard<std::mutex> guard(mutex_);
const size_t buffer_size = 4096; // 设定一个固定的缓冲区大小
char buffer[buffer_size];
ssize_t bytes_read = ::read(fd_, buffer, buffer_size);
if (bytes_read < 0) {
throw std::runtime_error("Failed to read from serial port");
}
return std::string(buffer, bytes_read);
}
private:
int fd_;
std::mutex mutex_;
};
使用示例
cpp
#include
#include
int main() {
try {
// 创建线程安全的串口对象
ThreadSafeSerialPort serial_port("/dev/ttyUSB0", B9600);
// 创建一个线程进行写操作
std::thread writer([&]() {
while (true) {
std::string data_to_write = "Hello Serial\n";
serial_port.write(data_to_write);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
});
// 创建另一个线程进行读操作
std::thread reader([&]() {
while (true) {
try {
std::string data_read = serial_port.read(); // 使用新的读取方法
if (!data_read.empty()) {
std::cout << "Read: " << data_read << std::endl;
}
} catch (const std::exception& ex) {
std::cerr << "Error: " << ex.what() << std::endl;
}
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
});
// 等待线程结束
writer.join();
reader.join();
} catch (const std::exception& ex) {
std::cerr << "Error: " << ex.what() << std::endl;
}
return 0;
}
在上述代码中,我添加了对read函数返回值的检查,以确保没有发生错误。如果::read返回负值,我们将抛出一个异常,以指示读取失败。这种方式在多线程环境中能够更好地处理错误,并提高代码的健壮性。