boost :: unique_lock,多次读取正在减慢编写器的速度

时间:2017-10-12 10:57:19

标签: c++ multithreading boost

我有一个应用程序,我使用boost::shared_mutex锁定在一个线程中编写cv::Mat,然后从许多其他线程调用它。

这很好用,但是所有的读取都会减慢作者的速度。我想,这是因为写操作正在等待所有读操作完成。是否有一种不同类型的boost锁定允许作者全速运行,有许多读者?或者我是否需要找到另一种解决方法呢?

我的相关代码是:

// writer.h

cv::Mat currentFrame;

typedef boost::shared_mutex Lock;
typedef boost::unique_lock< Lock > WriteLock;
Lock frameLock;

// writer.cpp

    WriteLock w_lock(frameLock);
    cv_img.copyTo(currentFrame);
    frameLock.unlock();

// reader.h

typedef boost::shared_mutex Lock;
typedef boost::shared_lock< Lock > ReadLock;

// reader.cpp

cv::Mat frame;

ReadLock r_lockz(writer->frameLock);
writer->currentFrame.copyTo(frame);
_lockz.unlock();

谢谢。

3 个答案:

答案 0 :(得分:1)

这里互斥的全部意义在于防止读/写冲突。当速度较慢的进程锁定资源时,减速正是您所期望的。

这个瓶颈将始终存在于您当前的方法中;你需要找到另一个。也许是不同类型的并发(多个读者/作者?)。

答案 1 :(得分:0)

您可以尝试双缓冲,即使用两个cv:Mat(帧)实例并在它们之间交替。

从“活动”帧读取时,可以(顺序)写入“非活动”帧(可以是并行)。写入新帧后,将其指定为“活动”,将另一帧指定为“非活动”。

共享状态:

cv::Mat currentFrame[2];
std::shared_mutex frameMutex[2];
std::mutex writeMutex;
std::atomic<int> activeFrame = 0;

作家实施:

std::unique_lock<std::mutex> writeLock(writeMutex);
const int writeFrame = activeFrame ^ 1;
std::unique_lock<std::shared_mutex> frameLock(frameMutex[writeFrame]);
cv_img.copyTo(currentFrame[writeFrame]);
activeFrame = writeFrame;

读者实施:

const int readFrame = activeFrame;
std::shared_lock<std::shared_mutex> frameLock(frameMutex[readFrame]); // lock shared
currentFrame[readFrame].copyTo(frame);

假设阅读明显快于写作。否则仍会有一些锁争用。

稍微重构代码并从“Writer”类中提取currentFrame(及相关锁)到单独的共享“State”类中可能是个好主意。

答案 2 :(得分:0)

而不是复制,只需分配它并创建一个新的,因为cv :: Mat本质上是一个shared_ptr

//writer.h    
cv::Mat currentFrame;

typedef boost::shared_mutex Lock;
typedef boost::unique_lock< Lock > WriteLock;
Lock frameLock;

//writer.cpp
WriteLock w_lock(frameLock);
currentFrame = cv_img;
frameLock.unlock();

//reader.h
typedef boost::shared_mutex Lock;
typedef boost::shared_lock< Lock > ReadLock;

//reader.cpp
cv::Mat frame;
ReadLock r_lockz(writer->frameLock);
frame = writer->currentFrame;
_lockz.unlock();

cv_img只是当前正在使用的缓冲区的前端。读者将获得一个缓冲区,该缓冲区不会改变读取周期(但可能与当前帧不同步直到它们完成),但它们的帧范围决定了每个缓冲区的寿命。

通过执行深层复制,您将在shared_ptr(cv :: Mat)中创建一个缓冲区,然后对其中的每个用户执行完整复制,而不是创建一个不可变的缓冲区,当每个人都完成时,该缓冲区将超出范围。锁定将保持修改。在旁注中,您可能希望在临界区内使用scoped_lock并在其周围放置大括号或范围。这种方式,如果你扔或忘记解锁它不会破坏一切。

{
    boost::scoped_lock(frameLock);
    currentFrame = cv_img;
}

如果你有很多争用,那么锁定时间(没有争用的锁不是“那么糟糕”)一个无锁队列可能会起作用

#include <boost/lockfree/spsc_queue.hpp>
// writer.h
using cv_queue_t = boost::lockfree::spsc_queue<cv::Mat>// cv::Mat might need this to be wrapped for contructor requirements
cv_queue_t cv_queue;
// writer.cpp
while( !cv_queue.push( cv_img ) ) { // could put a sleep in here }

// reader.cpp
while( !writer->cv_queue.pop( frame ) ) { // could put sleep in here } 
相关问题