Переменные-члены в классе раздуваются при использовании std :: thread - PullRequest
0 голосов
/ 22 июня 2019

Я определил базовый класс, используя std::thread.Для дочернего класса я выполняю некоторую инициализацию переменных-членов, а затем запускаю поток, используя m_thread.reset(new std::thread(&MyClass::ThreadMain, this));, где m_thread является членом MyClass.Цель этого класса - прочитать данные из последовательного порта и сообщить об этом родителю.Дескриптор очереди сообщений posix родителя передается в MyClass во время инициализации перед созданием потока.При запуске я получаю исключения и вижу, что переменные-члены, которые были инициализированы до того, как начался поток, кажутся недействительными с помощью функции watch в GDB.

Похоже, что первое сообщение на последовательном порту получено ипрошла проверку, чтобы дозвониться до SendToParent.При этом вызове кажется, что я теряю стек.Я попытался запустить cppcheck, чтобы увидеть, есть ли у меня утечки памяти или переполнения буфера, и ничего не нашел.

void MyClass::ThreadMain(void)
{
   ssize_t bytesRead = 0;
   UINT8 buffer[256];
   UINT8 message[256];
   BOOL partialMessage = FALSE;
   UINT8 messageIndex = 0;
   UINT8 payloadLength = 0;

   // read data from the UART
   while(1)
   {
      // the UART is setup to pend until data is available
      bytesRead = read(m_radioFileDescriptor, buffer, sizeof(buffer));
      if (FAIL == bytesRead)
      {
         LOG_SYSTEM_INFO("UART Read interrupted by a system call");
      }
      else if (bytesRead > 0)
      {
         // build the message
         for(ssize_t i = 0 ; i < bytesRead ; i++)
         {
            if (FALSE == partialMessage)
            {
               // have we found the start of the message?
               if(START_BYTE == buffer[i])
               {
                  // start of new message
                  messageIndex = 0;
                  message[messageIndex] = buffer[i];
                  partialMessage = TRUE;
                  messageIndex++;
               }
            }
            else
            {
               // keep building the message until the expected length is reached
               if(LENGTH_POSITION == messageIndex)
               {
                  // capture the expected message length
                  message[messageIndex] = buffer[i];
                  messageIndex++;
                  payloadLength = buffer[i];
               }
               else
               {
                  message[messageIndex] = buffer[i];
                  messageIndex++;

                  // check for expected length and end byte
                  if((messageIndex == payloadLength) && (END_BYTE == buffer[i]))
                  {
                     // this should be a valid message but need to confirm by checking for a valid checksum
                     UINT8 messageChecksum = message[messageIndex - CHKSUM_POS_FROM_END];
                     UINT8 calculatedChecksum = RadioProtocol::Instance().GenerateRadioChecksum(message, (payloadLength - CHKSUM_POS_FROM_END));
                     if (messageChecksum == calculatedChecksum)
                     {
                        SendToParent(message, payloadLength);
                     }
                     else
                     {
                        LOG_SYSTEM_ERROR("Checksum FAILURE");
                     }

                     // reset for the next message
                     partialMessage = FALSE;
                     messageIndex = 0;
                  }
                  else if((messageIndex == payloadLength) && (END_BYTE != buffer[i]))
                  {
                     // malformed message - throw out and look for start of next message
                     LOG_SYSTEM_ERROR("Bytes read exceeded expected message length");
                     partialMessage = FALSE;
                     messageIndex = 0;
                  }
               }
            }
         } // end for loop of bytes read on the port
      }
      else
      {
         LOG_SYSTEM_INFO("Read returned 0 bytes which is unexpected");
      }
   }
}

void MyClass::SendToParent(UINT8* pMsg, UINT8 size)
{
   if ((pMsg != NULL) && (m_parentQueueHandle > 0))
   {
      // message is valid - pass up for processing
      MsgQueueMessage msgToSend;

      msgToSend.m_msgHeader = UART_MESSASGE;
      bzero(msgToSend.m_msgData, sizeof(msgToSend.m_msgData));
      for (UINT8 i = 0; i < size; i++)
      {
         msgToSend.m_msgData[i] = pMsg[i];
      }

      if (FAIL == msgsnd(m_parentQueueHandle, &msgToSend, sizeof(msgToSend), IPC_NOWAIT))
      {
         LOG_SYSTEM_ERROR("FAILED to send message on queue");
      }
   }
}

Это действует так, как будто я выполняю переполнение буфера, но я просто не вижу его.Когда я устанавливаю точку останова на линии UINT8 messageChecksum = message[messageIndex - CHKSUM_POS_FROM_END];, все данные в окне просмотра отображаются действительными.Если я перейду к следующей строке, то данные, например, m_parentQueueHandle, сгорят.

Я впервые работаю с потоками c ++ 11 и особенно с c ++.Любая помощь или идеи будут оценены.

1 Ответ

0 голосов
/ 22 июня 2019

Я думаю, что нашел проблему. Я добавил кучу printfs и обнаружил, что вызывается деструктор для класса. Гораздо дальше у upstreamI родительский объект создавался как локальная переменная, и он выходил из области видимости. Это заставило ребенка выйти из области видимости, но потоки все еще работали. Мне, конечно, нужно очистить темы в деструкторе.

...