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

相关推荐
JAVA面经实录91716 小时前
Java企业级工程化·终极完整版背诵手册(无遗漏、全覆盖、面试+落地通用)
java·开发语言·面试
王老师青少年编程17 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【哈夫曼贪心】:合并果子
c++·算法·贪心·csp·信奥赛·哈夫曼贪心·合并果子
周杰伦fans17 小时前
AutoCAD .NET 二次开发:深入理解 EntityJig 的工作原理与正确实现
开发语言·.net
叼烟扛炮17 小时前
C++第二讲:类和对象(上)
数据结构·c++·算法·类和对象·struct·实例化
样例过了就是过了19 小时前
LeetCode热题100 最长公共子序列
c++·算法·leetcode·动态规划
Bat U19 小时前
JavaEE|多线程初阶(七)
java·开发语言
谭欣辰19 小时前
C++ 排列组合完整指南
开发语言·c++·算法
橙子也要努力变强20 小时前
信号捕捉底层机制-机理篇2
linux·服务器·c++
foundbug99920 小时前
自适应滤除直达波干扰的MATLAB实现
开发语言·算法·matlab