c++中串口的安全封装使用

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

相关推荐
明月看潮生14 分钟前
青少年编程与数学 02-003 Go语言网络编程 15课题、Go语言URL编程
开发语言·网络·青少年编程·golang·编程与数学
南宫理的日知录25 分钟前
99、Python并发编程:多线程的问题、临界资源以及同步机制
开发语言·python·学习·编程学习
逊嘘42 分钟前
【Java语言】抽象类与接口
java·开发语言·jvm
van叶~44 分钟前
算法妙妙屋-------1.递归的深邃回响:二叉树的奇妙剪枝
c++·算法
Half-up44 分钟前
C语言心型代码解析
c语言·开发语言
knighthood20011 小时前
解决:ros进行gazebo仿真,rviz没有显示传感器数据
c++·ubuntu·ros
Source.Liu1 小时前
【用Rust写CAD】第二章 第四节 函数
开发语言·rust
monkey_meng1 小时前
【Rust中的迭代器】
开发语言·后端·rust
余衫马1 小时前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng1 小时前
【Rust中多线程同步机制】
开发语言·redis·后端·rust