我有两个成员变量。
class MessageQueues {
....
char* m_InputBuffer;
uint32_t m_InputBufferSize;
....
};
我正在当前线程的一个函数中更新它们,甚至与调试器一起查看成员变量是否已更新。但是在另一个函数中,该函数在单独的线程中运行,成员变量包含垃圾。
所以,我有一个函数,它读取两个值并将它们写入两个成员变量,并在完成后触发另一个线程。
ErrorCode MessageQueue::handleIncomingMessage(char receiveBuffer[], const uint32_t bufferSize) {
ES_TRC3("started");
ErrorCode errorCode = ES_SUCCESS;
pthread_mutex_lock(&mutexMsgQueueIncoming);
m_InputBuffer = receiveBuffer;
m_InputBufferSize = bufferSize;
ES_TRC3("triggering and unlocking");
pthread_cond_signal(&msgQueueCondition);
pthread_mutex_unlock(&mutexMsgQueueIncoming);
ES_TRC3("triggered and unlocked");
return errorCode;
}
然后加入第二个成员函数,该函数将无限期地在单独的线程中运行并等待消息,
ErrorCode MessageQueue::runReceiver(void) {
ES_TRC3("started");
ErrorCode errorCode = ES_SUCCESS;
while(true)
{
ES_TRC3("waiting for input messages");
pthread_cond_wait(&msgQueueCondition, &mutexMsgQueueIncoming);
pthread_mutex_lock(&mutexMsgQueueIncoming);
ES_TRC3("will parse message");
if (strlen(m_InputBuffer) > 0UL) {
if ((errorCode = m_MsgProtocol->parseMessage(m_InputBuffer, m_InputBufferSize)) != ES_SUCCESS)
{
ES_TRC1("failed to parseMessage, error:%d", errorCode);
}
}
ES_TRC3("message parsed");
pthread_mutex_unlock(&mutexMsgQueueIncoming);
}
return errorCode;
}
借助调试器(以及日志消息),我可以看到变量的更新和触发以正确的顺序发生。因此,我无法弄清楚为什么在第二个函数中,成员变量似乎没有包含正确的值。我在某处读到有关“易失性”的内容。但是不要真的认为,这是正确的答案。我在这里做错什么了吗?
更新: 互斥锁在类之外,但在同一源文件中,像这样在顶部初始化。
pthread_mutex_t mutexMsgQueueIncoming = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t msgQueueCondition = PTHREAD_COND_INITIALIZER;
实际上,这很奇怪。当我在没有调试器的情况下运行程序时,似乎互斥体无法在runReceiver()函数中锁定。使用调试器,互斥锁被锁定,但成员变量包含垃圾。好的,我想应该对此进行调查。
答案 0 :(得分:1)
这里有错误:
while
循环处理。修复:
class MessageQueues {
....
char* m_InputBuffer;
uint32_t m_InputBufferSize;
uint32_t m_WriteGeneration = 0; // <--- a fix.
uint32_t m_ReadGeneration = 0; // <--- a fix.
....
};
ErrorCode MessageQueue::handleIncomingMessage(char receiveBuffer[], const uint32_t bufferSize) {
ES_TRC3("started");
ErrorCode errorCode = ES_SUCCESS;
pthread_mutex_lock(&mutexMsgQueueIncoming);
m_InputBuffer = receiveBuffer;
m_InputBufferSize = bufferSize;
++m_WriteGeneration; // <--- a fix.
ES_TRC3("triggering and unlocking");
pthread_cond_signal(&msgQueueCondition);
pthread_mutex_unlock(&mutexMsgQueueIncoming);
ES_TRC3("triggered and unlocked");
return errorCode;
}
ErrorCode MessageQueue::runReceiver(void) {
ES_TRC3("started");
ErrorCode errorCode = ES_SUCCESS;
while(true)
{
ES_TRC3("waiting for input messages");
pthread_mutex_lock(&mutexMsgQueueIncoming); // <--- a fix.
while(m_ReadGeneration == m_WriteGeneration) // <--- a fix.
pthread_cond_wait(&msgQueueCondition, &mutexMsgQueueIncoming); // <--- a fix.
m_ReadGeneration = m_WriteGeneration; // <--- a fix.
ES_TRC3("will parse message");
if (strlen(m_InputBuffer) > 0UL) {
if ((errorCode = m_MsgProtocol->parseMessage(m_InputBuffer, m_InputBufferSize)) != ES_SUCCESS)
{
ES_TRC1("failed to parseMessage, error:%d", errorCode);
}
}
ES_TRC3("message parsed");
pthread_mutex_unlock(&mutexMsgQueueIncoming);
}
return errorCode;
}
请注意,如果handleIncomingMessage
解锁互斥锁时两次调用runReceiver
,则此代码将丢失消息。您可能需要在此处放置一个消息队列,而不是存储最后一条消息(即,您有一个大小为1的队列,该队列在溢出时会丢弃旧元素)。
该代码还需要检查pthread函数返回的错误代码。这很繁琐,最好使用C ++ 11 std::mutex
,std::condition_variable
,std::unique_lock
为您做检查。在C ++ 98中,您可以使用boost
个等效项。