簡體   English   中英

為什么調用notify后等待線程沒有喚醒?

[英]Why a waiting thread does not wake up after calling notify?

我正在嘗試模擬一個以特定幀速率輸出數據的傳感器,而另一個傳感器正在等待准備好數據,當它准備好時,它會在本地復制並處理它。

Sensor sensor(1,1000);
Monitor monitor;

// Function that continuously reads data from sensor
void runSensor()
{
    // Initial delay
    std::this_thread::sleep_for(std::chrono::milliseconds(2000));

    for(int i = 0; i < SIZE_LOOP; i++)
    {
        monitor.captureData<Sensor>(sensor, &Sensor::captureData);
    }
}

// Function that waits until sensor data is ready
void waitSensor()
{
    monitor.saveData<Sensor>(sensor, &Sensor::saveData);
}

// Main function
int main()
{
    // Threads that reads at some frame rate data from sensor
    std::thread threadRunSensor(runSensor);

    // Processing loop
    for(int i = 0; i < SIZE_LOOP; i++)
    {
        // Wait until data from sensor is ready
        std::thread threadWaitSensor(waitSensor);

        // Wait until data is copied
        threadWaitSensor.join();

        // Process synchronized data while sensor are throwing new data
        std::cout << "Init processing (" << sensor.getData() << /*"," << sensor2.getData() << */")"<< std::endl;
        // Sleep to simulate processing load
        std::this_thread::sleep_for(std::chrono::milliseconds(10000 + (rand() % 1000)));
        //std::this_thread::sleep_for(std::chrono::milliseconds(500));
        std::cout << "End processing" << std::endl;
    }

    return 0;
}

這是傳感器 class。 它有兩種方法。 一種生成數據,另一種在本地復制數據。

class Sensor
{
    private:

    int counter;
    int id;
    int frameRate;
    int dataCaptured;
    int dataSaved;

    public:

    Sensor(int f_id, int f_frameRate)
    {
        id = f_id;
        counter = 0;
        frameRate = f_frameRate;
    };

    ~Sensor(){};

    void captureData()
    {
        dataCaptured = counter;
        counter ++;
        std::cout << "Sensor" << id << " (" << dataCaptured << ")"<< std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(frameRate + (rand() % 500)));
    };

    void saveData()
    {
        dataSaved = dataCaptured;
        std::cout << "Copying sensor" << id << " (" << dataSaved << ")"<< std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(1 + (rand() % 5)));
    }

    int getData()
    {
        return dataSaved;
    }
};

然后是一個 class 監視器,可確保這些操作受到保護以防止並發訪問。

#include <iostream> 
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <cstdlib>

#define SIZE_LOOP 1000

class Monitor
{
private:

    std::mutex m_mutex;
    std::condition_variable m_condVar;
    bool m_isReady;

public:

    Monitor()
    {
        init();
    };

    ~Monitor()
    {
    };

    void init() 
    {
        m_isReady = false;
    };

    template<class T>
    void captureData(T& objectCaptured, void (T::* f_captureFunction_p)())
    {
        // Lock read
        std::unique_lock<std::mutex> lock = std::unique_lock<std::mutex>(m_mutex);
        (objectCaptured.*f_captureFunction_p)();
        m_isReady = true;
        m_condVar.notify_one();
        lock.unlock();
    };

    template<class T>
    void saveData(T& objectSaved, void(T::*f_saveFunction_p)())
    {
        std::unique_lock<std::mutex> lock = std::unique_lock<std::mutex>(m_mutex);
        while(!m_isReady)
        {
            m_condVar.wait(lock);
        }
        (objectSaved.*f_saveFunction_p)();
        m_isReady = false;
        lock.unlock();
    };
};

誰能告訴我,如果傳感器通知每個幀速率,為什么等待線程不會喚醒?

這個想法是在這個工作流中有兩個線程:

  • ThreadCapture 捕獲數據,在數據捕獲完成時持續通知 ThreadProcessing。
  • 僅當當前捕獲的數據在 ThreadProcessing 上復制時,ThreadCapture 必須等待捕獲新數據。
  • ThreadProcessing 等待新捕獲的數據,制作本地副本,通知 ThreadCapture 副本已完成並處理數據。
  • 在 ThreadProcessing 上制作本地副本以允許 ThreadCapture 可以在 ThreadProcessing 處理時捕獲新數據。

最后我找到了解決方案,在捕獲后添加了一個等待步驟,以便有時間保存數據

template<class T>
void captureData(T& objectCaptured, void (T::* f_captureFunction_p)())
{
    std::unique_lock<std::mutex> lockReady = std::unique_lock<std::mutex>(m_mutexReady, std::defer_lock);
    std::unique_lock<std::mutex> lockProcess = std::unique_lock<std::mutex>(m_mutexProcess, std::defer_lock);

    // Lock, capture, set data ready flag, unlock and notify
    lockReady.lock();
    (objectCaptured.*f_captureFunction_p)();
    m_isReady = true;
    lockReady.unlock();
    m_conditionVariable.notify_one();
    
    // Wait while data is ready and it is not being processed
    lockReady.lock();
    lockProcess.lock();
    while(m_isReady && !m_isProcessing)
    {
        lockProcess.unlock();
        m_conditionVariable.wait(lockReady);
        lockProcess.lock();
    }
    lockProcess.unlock();
    lockReady.unlock();
};

template<class T>
void saveData(T& objectSaved, void(T::*f_saveFunction_p)())
{
    std::unique_lock<std::mutex> lockReady(m_mutexReady, std::defer_lock);
    std::unique_lock<std::mutex> lockProcess(m_mutexProcess, std::defer_lock);

    // Reset processing
    lockProcess.lock();
    m_isProcessing = false;
    lockProcess.unlock();

    // Wait until data is ready
    lockReady.lock();
    while(!m_isReady)
    {
        m_conditionVariable.wait(lockReady);
    }

    // Make a copy of the data, reset ready flag, unlock and notify
    (objectSaved.*f_saveFunction_p)();
    m_isReady = false;
    lockReady.unlock();
    m_conditionVariable.notify_one();

    // Set processing
    lockProcess.lock();
    m_isProcessing = true;
    lockProcess.unlock();
};
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM