赞
踩
固定缓冲区大小:在这种情况下,你将缓冲区大小固定为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返回负值,我们将抛出一个异常,以指示读取失败。这种方式在多线程环境中能够更好地处理错误,并提高代码的健壮性。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。