std::thread 使用 notify_one() 函数时即使有谓词也不会唤醒

std::thread not waking up when using notify_one() function even with predicate

我一直在尝试使用 Windows API 在串行端口上写入周期性和非周期性消息。我的代码架构如下:

主线程启动如下:

出于调试目的,主线程还在另一个构建消息的函数上循环了几次,并以与计时器每 500 毫秒相同的方式通知“消息发送线程”。这是代码


#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <Windows.h>

std::condition_variable m_cvSend;
std::mutex m_mtxSend;
std::thread m_threadSendMessage;
std::thread m_threadPeriodicMessage;
char messageToSend[512] = { 0 };
bool newMessage = false;
bool threadRunning = false;
int count = 0;

void SendPeriodicMessage();
void SendFoo();
void sendMessageRun(void);

int main()
{
    threadRunning = true;

    //Start message sending thread
    m_threadSendMessage = std::thread(&sendMessageRun);
    m_threadPeriodicMessage = std::thread(&SendPeriodicMessage);

    Sleep(1000);
    while (count < 20) {
        SendFoo();
        Sleep(500);
        count++;
    }

    m_threadSendMessage.join();
}

void sendMessageRun(void) {

    std::unique_lock<std::mutex> lck(m_mtxSend);
    DWORD bytesEcrits = 0;
    while (threadRunning == true) {
        m_cvSend.wait(lck, [&] {return newMessage; });
        std::cout << "I'm HERE" << std::endl;
        std::cout << messageToSend << std::endl;

        //Send message over Serial port
        //NOT RELEVANT FOR THE ISSUE

        //Clean buffer
        Sleep(20);
        memset(messageToSend, 0, sizeof(messageToSend));
        bytesEcrits = 0;
        newMessage = 0;
    }

}

//Envoi d'une consigne de pointage
void SendPeriodicMessage() {

    while (true) {

        //Send every 100 ms
        Sleep(100);

        std::lock_guard<std::mutex> lkEnvoi(m_mtxSend);

        strcpy_s(messageToSend, "Thread 1");

        //Flag for spurious wake ups
        newMessage = true;

        //// Debug 
        //std::cout << "Message to be sent periodically" << std::endl;
        //std::cout << messageToSend << std::endl;

        //End of critical section
        //Notify sending thread

        m_cvSend.notify_one();
    }
}

void SendFoo() {

    std::lock_guard<std::mutex> lkEnvoi(m_mtxSend);

    char countChar[3] = { 0 };

    _itoa_s(count, countChar, 10);

    strcpy_s(messageToSend, "foo");

    strcat_s(messageToSend, countChar);

    //Flag for spurious wake ups
    newMessage = true;

    //End of critical section
    //Notify sending thread

    m_cvSend.notify_one();
}

虽然 运行 这个,我发现 foo 函数有时不会唤醒线程。其实函数应该是通过notify_one()函数来通知线程唤醒的。但是,我想 wait() 函数没有解锁,因为我没有在控制台上观察到另一个“我在这里”。

我已经看到用 notify_one() 唤醒一个线程是原子完成的,所以我不明白为什么它不会在干扰之间完成。

我尝试使用 Windows API 更改线程优先级,但它不起作用。

对于这第一个 post!

的一些帮助将不胜感激

谢谢!

您有两个可以“发送”消息的不同线程。这些线程是否已经有待处理的消息(例如 newMessage==true;)。

notify_one 最终会通知接收线程,但不能保证它会立即通知。

在你的两个发送函数中添加一个 assert(! newMessage);,你可能会看到一个被命中。