不在条件变量中使用谓词导致减速

时间:2018-01-03 14:24:29

标签: c++ multithreading concurrency predicate condition-variable

我正在尝试构建一个允许其他线程检索帧的相机包装器,而包装器处理单独线程中的所有处理。 使用条件变量来通知新帧的其他线程已准备好的主要目的是使其他线程不会两次获得相同的帧。在某种程度上,这是生产者 - 消费者问题的一个例子。

在初始化期间,我初始化一个线程来进行捕获和处理:

int PiCamera::Init(){
    camera_on_ = true;
    capture_thread_ = std::thread(&PiCamera::RetrieveFrames, this);
    return 0;
}

其中RetrieveFrames是:

int PiCamera::RetrieveFrames1(){
while(camera_on_){
    camera_.grab();
    frame_ready_ = true;
    ready_condition_.notify_all(); // Notify on condition variable
}
return 0;
}

现在当有一个线程试图获取一个帧时,需要调用的所有线程都是:

int PiCamera::GetFrame1(cv::Mat &image){
    // Lock mutex
    std::unique_lock<std::mutex> mutex_lock(ready_mutex_);
    ready_condition_.wait(mutex_lock, [this](){return frame_ready_;});
    camera_.retrieve(image);
    frame_ready_ = false;
    // Unlock mutex
    mutex_lock.unlock();
    return 0;
}

现在,如果两个线程调用GetFrame函数,则每个线程都只能获取alernate帧。但是,我希望任何数量的传入线程能够在可用时尽快获得最新帧。

在这里,似乎这就像是一个有多个消费者的生产者 - 消费者问题,但所有消费者都应该能够获得最新的数据,而且不应该两次读取相同的数据。

因此,我做了以下更改:

int PiCamera::RetrieveFrames2(){
    while(camera_on_){
        camera_.grab();
        // frame_ready_ = true;
        ready_condition_.notify_all(); // Notify on condition variable
    }
    return 0;
}

int PiCamera::GetFrame2(cv::Mat &image){
    // Lock mutex
    std::unique_lock<std::mutex> mutex_lock(ready_mutex_);
    // ready_condition_.wait(mutex_lock, [this](){return frame_ready_;});
    ready_condition_.wait(mutex_lock);
    camera_.retrieve(image);
    // frame_ready_ = false;
    // Unlock mutex
    mutex_lock.unlock();
    return 0;
}

现在我可以使用2个线程来获取相同的帧,但我注意到在检索帧时出现了一些减速。

我跑的程序有点像这样:

PiCamera camera();
camera.Init();
cv::Point2f centroid_location;
cv::Mat image;
float time1[NFRAMES] = {};
float time2[NFRAMES] = {};
float time3[NFRAMES] = {};
timeval tstart, tend, t1, t2, t3;

for(int frame=0;frame<NFRAMES;frame++){
    gettimeofday(&t1, nullptr);
    camera->GetFrame(image);
    gettimeofday(&t2, nullptr);
    time1[frame] = ElapsedSec(t1, t2)*1000;
    GetCentroid(image, centroid_location);
    // Just to increase workload
    GetCentroid(image, centroid_location);
    gettimeofday(&t3, nullptr);
    time2[frame] = ElapsedSec(t2, t3)*1000;
}

gettimeofday(&tend, nullptr);
float total_time = ElapsedSec(tstart, tend);
float fps = (float)NFRAMES/total_time;
std::cout << "Camera took " << total_time << " seconds at " << fps << " FPS\n";
std::cout << "t1 " << ArrayMean(time1, NFRAMES) << " t2 " << ArrayMean(time2, NFRAMES) << '\n';

相机能够以120FPS的帧速率抓取,所以我希望我能够以120FPS处理帧。

当我使用 RetrieveFrames1 GetFrames1 运行程序时,我明白了:

Camera took 8.39579 seconds at 119.107 FPS
t1 0.367703 t2 8.02553

但是,当我使用 RetrieveFrames2 GetFrames2 进行此测试时:

Camera took 13.7088 seconds at 72.946 FPS
t1 4.74955 t2 8.95662

即使我打电话给 GetCentroid ,我也会得到以下结果:

Camera took 8.29365 seconds at 120.574 FPS
t1 3.98624 t2 4.30591

Camera took 8.94322 seconds at 111.817 FPS
t1 4.43984 t2 4.50159

为什么我的线程需要花费更长的时间才能在条件变量上等待,因为我所做的只是删除谓词?

0 个答案:

没有答案