串行端口与c ++

时间:2018-01-09 14:18:51

标签: c++ multithreading class serial-port

这是我的简化类,用于检测完整程序中的问题:

SimpleThread.h

class SimpleThread {
public:

    SimpleThread();
    ~SimpleThread();

    void startThread();
    void threadFn();

private:

    SerialPort mySerial;

    std::thread myThread;
    int count;
    std::mutex myMutex;
};

SimpleThread.cpp

SimpleThread::SimpleThread(): mySerial("/dev/ttyACM0") {
    count = 0;
    mySerial.Open(//Here correct params//);
}

SimpleThread::~SimpleThread() {}

void SimpleThread::threadFn() {

    char cp;

    while (true) {
        cp = mySerial.ReadByte(0);
        std::cout << count++ << " " << cp << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

void SimpleThread::startThread() {
    myThread = std::thread(&SimpleThread::threadFn, this);
    myThread.detach();
}

的main.cpp

int main() {

    SimpleThread thr;
    thr.startThread();

    while (true) {
        std::cout << "Waiting 5 seconds" << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(5));
    }
}

我的例子的主要思想:我使用类成员函数作为线程函数从打开的串口读取数据。没有从串口读取使用这个类没有问题:主循环每隔5秒打印一次消息,而线程循环(类中的函数)打印5个数字。

现在我想实现从串口读取,而我的主循环将要做其他事情。为了以串行方式进行读/写,我使用了this而不是最新的串行库。

在这种情况下,类开始对我意外工作:主循环(应该每5秒显示一次消息)显示其消息更快然后线程循环(大约40次,1秒)。此代码工作错误导致主循环在1秒内(读取字节后)打印消息40次,尽管有睡眠功能。

所以我的问题是:问题的根源在哪里?我应该使用另一个串行库还是有一些与我不知道的中断相关的功能?

编辑:如果我使用下一个循环进行读取并检查数据是否可用,则在每个读取字节后打印主循环。看起来在线程循环中读取字节会中断主循环并取消休眠。

if ( mySerial.IsDataAvailable() ) {
    cp = mySerial.ReadByte(0);
    std::cout << count++ << " " << cp << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

编辑2:此外,我测试只是打开串口,但没有读取串行循环(在两秒钟内线程循环中更改暂停)

if ( mySerial.IsDataAvailable() ) {
    std::cout << count++ << " " << cp << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));
}

在这种情况下,主循环每秒打印一次。只有在没有打开串口的情况下才会出现问题。

1 个答案:

答案 0 :(得分:0)

libserial使用基于信号的异步I / O(确切地说SIGIO)并且GCC 5中存在一个错误(#66803std::this_thread::sleep_for被信号打断了。它已在GCC 6中修复。

可能的解决方案是:

  • 将编译器升级到GCC 6+或clang / LLVM。
  • 使用错误66803中提到的解决方法或尝试sleep_until

    auto wakeup_time = std::chrono::steady_clock::now() + std::chrono::seconds(1);
    std::this_thread::sleep_until(wakeup_time);
    
  • 使用阻止I / O(我相信您只需将串行设备作为文件打开并从中读取)。