如何使用多个boost :: thread对象管理文件描述符的并发读取。 (提升线程管理)

时间:2014-04-28 12:33:09

标签: c++ linux multithreading boost

我正在编写一个条形码阅读器的应用程序,我有几种方法可以同步执行。作为初始点,我将同时从设备读取数据。以下是我的情景。

环境 操作系统:CENTOS 6.3(LINUX) 提升:1.41

  1. 始终等待来自设备的解码数据(条形码扫描数据)
  2. 发送已接收解码数据的确认
  3. 同时向设备发送请求
  4. 并从设备获得回复或确认
  5. 为了数据读取目的,我有2种方法,我有1种方法将命令发送到解码器。我正在尝试使用来自互联网的boost :: thread示例,但我仍然无法理解这个场景。以下是我的申请中的示例代码。在这种情况下,请告诉我线程管理。

    我在下面使用OOP方法是DeviceRS232.cpp类

    中的方法
    // Open and set attributes for serial port
    int DeviceRS232::openSerialPort()
    {
        int fd, baudr, status, portStatus;
        setDefaultAttributes();
    
        switch(getBaudRate())
        {
            case      50 : baudr = B50;
                           break;
            case      75 : baudr = B75;
                           break;
            case     110 : baudr = B110;
                           break;
            case     134 : baudr = B134;
                           break;
            case     150 : baudr = B150;
                           break;
            case     200 : baudr = B200;
                           break;
            case     300 : baudr = B300;
                           break;
            case     600 : baudr = B600;
                           break;
            case    1200 : baudr = B1200;
                           break;
            case    1800 : baudr = B1800;
                           break;
            case    2400 : baudr = B2400;
                           break;
            case    4800 : baudr = B4800;
                           break;
            case    9600 : baudr = B9600;
                           break;
            case   19200 : baudr = B19200;
                           break;
            case   38400 : baudr = B38400;
                           break;
            case   57600 : baudr = B57600;
                           break;
            case  115200 : baudr = B115200;
                           break;
            case  230400 : baudr = B230400;
                           break;
            case  460800 : baudr = B460800;
                           break;
            case  500000 : baudr = B500000;
                           break;
            case  576000 : baudr = B576000;
                           break;
            case  921600 : baudr = B921600;
                           break;
            case 1000000 : baudr = B1000000;
                           break;
            default      : printf("invalid baudrate\n");
                           return(1);
                           break;
        }
    
        //  Open serial port
        fd = open(getSerialPort().c_str(),  O_RDWR | O_NOCTTY | O_NDELAY);
        if(fd == -1)
        {
            printf("Unable to open serial port...\n");
            perror(getSerialPort().c_str());
            return 1;
        }
    
        fdRS232 = fd;
    
        fcntl(fdRS232, F_SETFL, FNDELAY);
        status = tcgetattr(fdRS232, &oldSerialPortSetting);
        if(status == -1)
        {
            close(fdRS232);
            printf("Unable to get serial port attributes...\n");
            return 1;
        }
    
        memset(&newSerialPortSetting, 0, sizeof(newSerialPortSetting));
        newSerialPortSetting.c_cflag = baudr | CS8 | CLOCAL | CREAD | CRTSCTS; // | CRTSCTS
        newSerialPortSetting.c_iflag = IGNPAR;
        newSerialPortSetting.c_oflag = 0;
        newSerialPortSetting.c_lflag = 0;
        newSerialPortSetting.c_cc[VMIN] = 0;
        newSerialPortSetting.c_cc[VTIME] = 0;
    
        ChangeCTS(fdRS232, 0);
        ChangeRTS(fdRS232, 0);
    
    
      return 0;
    }
    
    
    // send data to the decoder
        int DeviceRS232::sendDataBuffer(const unsigned char *dataBuffer, size_t bufferSize)
        {
            int sentSize;
    
            ChangeRTS(fdRS232, 1);
            ChangeCTS(fdRS232, 1);
    
            while(true)
            {
                sentSize = write(fdRS232, dataBuffer, bufferSize);
                if(sentSize > 0)
                    break;
            }
    
            hasCommandSent = true;
            sleep(1);
    
            return sentSize;
        }
    
    // Receive response from the decoder    
        int DeviceRS232::receiveDataBuffer(unsigned char *dataBuffer, size_t bufferSize)
        {
            unsigned char recvBuffer[251];
            unsigned char *ptrChar;
            int nBytes, portStatus;
            int inputBufSize = 0;
    
            ChangeCTS(fdRS232, 0);
            ChangeRTS(fdRS232, 0);
    
            while(inputBufSize <= 0)
            {
                ioctl(fdRS232, FIONREAD, &inputBufSize);
                usleep(1);
            }
    
            //TEST PURPOSES
            //sleep(1);
    
    
            if(inputBufSize > 0)
            {
                memset(recvBuffer, 0x00, sizeof(recvBuffer));
                nBytes = read(fdRS232, recvBuffer, 251);
                if(nBytes < 0)
                {
                    printf("Unable to receive data...\n");
                    perror("/dev/ttyS0");
                }
    
                std::cout << "RECV Length: " << nBytes << std::endl;
                for(int i=0; i<nBytes; i++)
                {
                    std::cout << "recvBuffer[" << (int)i << "]: ";
                    printf("%x\n", recvBuffer[i]);
                }
                std::cout << "-----------------------------------" << std::endl;
    
                //ChangeRTS(fdRS232, 1);
                //sleep(1);
            }
    
            strcpy((char *)dataBuffer, (char *)recvBuffer);
            inputBufSize = 0;
    
            return nBytes;
    
        }
    
    // Receive decoded data from decoder.    
        int DeviceRS232::receiveDecodedData(unsigned char *dataBuffer, size_t bufferSize)
        {
            unsigned char recvBuffer[251];
            unsigned char *ptrChar;
            int nBytes, portStatus;
            int inputBufSize = 0;
    
            ChangeCTS(fdRS232, 0);
            ChangeRTS(fdRS232, 0);
    
            while(inputBufSize <= 0)
            {
                ioctl(fdRS232, FIONREAD, &inputBufSize);
                usleep(1);
            }
    
            //  TEST PURPOSES
            //sleep(1);
    
    
    
            if(inputBufSize > 0)
            {
                int decodePacketLen;
                //unsigned char
                memset(recvBuffer, 0x00, sizeof(recvBuffer));
                nBytes = 0;
    
                while(nBytes < ((int)recvBuffer[0] + 2))
                {
                    int index = 0;
                    if(nBytes != 0)
                        index = nBytes - 1;
    
                    nBytes += read(fdRS232, &recvBuffer[index], 251);
                    if(nBytes == ((int)recvBuffer[0] + 2))
                        break;
                }
    
                std::cout << "RECV Length: " << (int)recvBuffer[0] << std::endl;
                for(int i=0; i<nBytes; i++)
                {
                    std::cout << "recvBuffer[" << (int)i << "]: ";
                    printf("%x\n", recvBuffer[i]);
                }
                std::cout << "-----------------------------------" << std::endl;
    
                //ChangeRTS(fdRS232, 1);
                //ChangeCTS(fdRS232, 1);
                //sleep(1);
            }
    
            //strcpy((char *)dataBuffer, (char *)recvBuffer);
            memcpy((char *)dataBuffer, recvBuffer, sizeof(recvBuffer)/sizeof(recvBuffer[0]));
            inputBufSize = 0;
    
            return nBytes;
    
        }
    
    // Method I am going to use for concurrent reading
    
    void DeviceRS232::startReadTread()
    {
        boost::thread *dataReader1, *dataReader2;
        dataReader1 = new boost::thread(boost::bind(&DeviceRS232::decodedDataReadThread, this));
    
        dataReader2 = new boost::thread(boost::bind(&DeviceRS232::commandResponseReadThread, this));
        dataReader2->join();
    }
    
    
    // Finally I am hoping to create and call to thread handling method from main method.
    int main()
    {
        DeviceRS232 dev_rs232;
        dev_rs232.setDefaultAttributes();
        dev_rs232.openSerialPort();
    
        dev_rs232.startReadTread();
    
        return 0;
    }
    

    我可以上传完整的程序以供进一步参考。

2 个答案:

答案 0 :(得分:2)

通过使用Boost Asio的串行通信选项,您可以更轻松地实现John Zwinck所提到的。

这有使您的代码可移植的神奇好处

  

串行端口可在所有POSIX平台上使用。对于Windows,串行端口仅在使用I / O完成端口后端的编译时可用(这是默认设置)。程序可以测试宏BOOST_ASIO_HAS_SERIAL_PORT以确定它们是否受支持。

答案 1 :(得分:0)

您应该使用基于事件的解决方案,如select(),epoll(),WaitForMultipleEvents等,而不是在单独的线程中旋转等待读取数据。这样您就可以避免浪费CPU内核进行读取,并且避免使用互斥体,并在数据可供读取时准确唤醒。