简体   繁体   English

为什么调用notify后等待线程没有唤醒?

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

I am trying to simulate a sensor that outputs data at a certain frame rate while another is waiting to have a data ready and when it is ready it copies it locally and processes it.我正在尝试模拟一个以特定帧速率输出数据的传感器,而另一个传感器正在等待准备好数据,当它准备好时,它会在本地复制并处理它。

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;
}

This is the sensor class.这是传感器 class。 It has two methods.它有两种方法。 One that generates the data and other that copies the data locally.一种生成数据,另一种在本地复制数据。

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;
    }
};

Then there is a class Monitor that ensures these operations are protected to concurrent accesses.然后是一个 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();
    };
};

Can anyone tell me why the waiting thread does not wakeup if the sensor is notifyng every frame rate?谁能告诉我,如果传感器通知每个帧速率,为什么等待线程不会唤醒?

The idea is having two threads with this workflow:这个想法是在这个工作流中有两个线程:

  • ThreadCapture captures a data consinuously notifying to ThreadProcessing when the data capture is done. ThreadCapture 捕获数据,在数据捕获完成时持续通知 ThreadProcessing。
  • ThreadCapture must waits to capture a new data only if the current captured data is being copied on ThreadProcessing.仅当当前捕获的数据在 ThreadProcessing 上复制时,ThreadCapture 必须等待捕获新数据。
  • ThreadProcessing waits to a new captured data, makes a local copy, notifies to ThreadCapture that the copy is done and process the data. ThreadProcessing 等待新捕获的数据,制作本地副本,通知 ThreadCapture 副本已完成并处理数据。
  • The local copy is made on ThreadProcessing to allow ThreadCapture can capture new data while ThreadProcessing is processing.在 ThreadProcessing 上制作本地副本以允许 ThreadCapture 可以在 ThreadProcessing 处理时捕获新数据。

Finally I found the solution adding a waiting step after the capture to give time to save data最后我找到了解决方案,在捕获后添加了一个等待步骤,以便有时间保存数据

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.

相关问题 为什么 conditional_variable::notify_all 可能不会唤醒任何线程? - Why conditional_variable::notify_all may not wake up any thread? pthread_unlock_mutex不唤醒等待的线程 - pthread_unlock_mutex doesn't wake up waiting thread 在特定时间后唤醒线程 - Wake up a thread after a specific time 如果没有线程需要唤醒,是否需要获取锁并通知condition_variable? - Is it necessary to acquire the lock and notify condition_variable if no thread needs to wake up? 使用set_alert_notify唤醒主线程的正确方法是什么? - What's a proper way to use set_alert_notify to wake up main thread? 线程何时从condition.wait()中唤醒 - when does a thread wake up from condition.wait() std :: conditional_variable :: notify_all不会唤醒所有线程 - std::conditional_variable::notify_all does not wake up all the threads 唤醒线程非常耗时 - Wake up of the thread is time consuming 虚假唤醒是否会解除所有等待线程的阻塞,甚至是不相关的线程? - Does a spurious wake up unblock all waiting threads, even the unrelated ones? 使用 pthread_cond_wait 等待的线程在收到信号后需要多长时间才能唤醒? 我如何估计这个时间? - How much time it takes for a thread waiting with pthread_cond_wait to wake after being signaled? how can I estimate this time?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM