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

相关推荐
cheems952717 分钟前
锁策略的介绍
java·开发语言
清水白石00818 分钟前
《Python × 数据库:用 SQLAlchemy 解锁高效 ORM 编程的艺术》
开发语言·python·json
风中月隐26 分钟前
C语言中以坐标的方式图解“字母金字塔”的绘制
c语言·开发语言·算法·字母金子塔·坐标图解法
崇山峻岭之间26 分钟前
C++ Prime Plus 学习笔记041
c++·笔记·学习
_风华ts29 分钟前
虚函数与访问权限
c++
Arva .30 分钟前
说说线程的生命周期和状态
java·开发语言
1001101_QIA33 分钟前
C++中不能复制只能移动的类型
开发语言·c++
tryxr38 分钟前
HashTable、HashMap、ConcurrentHashMap 之间的区别
java·开发语言·hash
serendipity_hky40 分钟前
【go语言 | 第5篇】channel——多个goroutine之间通信
开发语言·后端·golang
无事好时节43 分钟前
Linux 线程
java·开发语言·rpc