C++ Caffe特征提取阻止其他执行线程(Qt/C+;+;)
背景 我正在开发一个具有三个线程的Qt应用程序:C++ Caffe特征提取阻止其他执行线程(Qt/C+;+;),c++,multithreading,qt,blocking,caffe,C++,Multithreading,Qt,Blocking,Caffe,背景 我正在开发一个具有三个线程的Qt应用程序:main、thread1和thread2 main创建、启动并显示thread1的结果,以及 thread2,同时迭代地向它们输入 thread1每n次执行一次密集计算(~1s) 输入,忽略所有其他输入。大部分时间用于特征提取 使用 thread2对每个输入执行快速计算(~20ms)。但是 每n+1个输入取决于将输入n馈送至thread1的输出 在线程执行期间,当使用Caffe网络提取特征时,thread1似乎会阻止thread2。但是,thr
main
、thread1
和thread2
创建、启动并显示main
的结果,以及thread1
,同时迭代地向它们输入thread2
每n次执行一次密集计算(~1s) 输入,忽略所有其他输入。大部分时间用于特征提取 使用thread1
对每个输入执行快速计算(~20ms)。但是 每n+1个输入取决于将输入n馈送至thread2
的输出thread1
thread1
似乎会阻止thread2
。但是,thread1
在其他处理步骤(例如网络输入预处理)中不会阻止thread2
起初,我认为这是由未满足的依赖关系引起的:即thread1
阻塞thread2
,因为输入(例如)2n+1已准备好由thread2
处理,但输入2n尚未由thread1
完全处理
然而,通过分析执行流,我注意到在满足依赖关系时出现了这种“阻塞”行为:即,如果n=10,thread2
将在输入15处暂停执行,而thread1
从输入20中提取Caffe特征
问题
在Caffe特征提取期间,如何防止thread2
阻塞thread1
代码
下面是我的代码的精简版本,它显示了我程序的关键组件和逻辑
我已经在评论中强调了这个问题!!!问题:…,可在thread1worker.cpp
和featureengine.cpp
中找到
main.cpp:
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
qRegisterMetaType<Mat>("Mat");
Camera camera; // grabs camera frame every 30ms, emitting newFrame(frame)
/* thread1 */
QThread* thread1 = new QThread();
Thread1Worker* thread1_worker = new Thread1Worker();
thread1_worker->moveToThread(thread1);
QThread::connect(&camera, SIGNAL(newFrame(Mat)),
thread1_worker, SLOT(doWork(Mat)));
QThread::connect(thread1, SIGNAL(finished()),
thread1_worker, SLOT(deleteLater()));
QThread::connect(thread1, SIGNAL(finished()),
thread1, SLOT(deleteLater()));
/* thread2 */
ImageQueue* thread2_images = new ImageQueue();
QThread::connect(camera, SIGNAL(newFrame(Mat)),
thread2_images, SLOT(add(Mat)));
QThread* thread2 = new QThread();
Thread2Worker* thread2_worker = new Thread2Worker(thread2_images);
thread2_worker->moveToThread(thread2);
QThread::connect(thread2_worker, SIGNAL(workFinished(OutputType)),
thread2_worker, SLOT(addThread1Result(OutputType)));
QThread::connect(thread2, SIGNAL(finished()),
thread2_worker, SLOT(deleteLater()));
QThread::connect(thread2, SIGNAL(finished()),
thread2, SLOT(deleteLater()));
/* start threads */
thread1->start();
thread2->start();
camera->start();
return app.exec();
}
intmain(intargc,char*argv[])
{
QApplication应用程序(argc、argv);
qRegisterMetaType(“Mat”);
Camera Camera;//每30毫秒抓取一帧,发出新帧(帧)
/*螺纹1*/
QThread*thread1=新的QThread();
Thread1Worker*thread1_worker=新的Thread1Worker();
thread1\u worker->moveToThread(thread1);
QThread::连接(&摄像头,信号(新帧(Mat)),
螺纹1_工,槽(销钉(垫));
QThread::connect(线程1,信号(finished()),
线程1_worker,插槽(deleteLater());
QThread::connect(线程1,信号(finished()),
线程1,插槽(deleteLater());
/*螺纹2*/
ImageQueue*thread2_images=新建ImageQueue();
QThread::connect(摄像头、信号(新帧(Mat)),
螺纹2_图像,插槽(添加(垫));
QThread*thread2=新的QThread();
Thread2Worker*thread2\u worker=新的Thread2Worker(thread2\u图像);
thread2\u worker->moveToThread(thread2);
QThread::connect(thread2_worker,信号(workFinished(OutputType)),
线程2_工作线程,插槽(addThread1Result(OutputType));
QThread::connect(线程2,信号(finished()),
线程2_工作线程,插槽(deleteLater());
QThread::connect(线程2,信号(finished()),
线程2,插槽(deleteLater());
/*开始线程*/
thread1->start();
thread2->start();
摄像头->开始();
返回app.exec();
}
thread1worker.cpp:
Thread1Worker::Thread1Worker()
{
thread1_interval = 10; // this is "n"
is_initialized = false;
}
void Thread1Worker::doWork(Mat frame)
{
if (!is_initialized)
initialize();
// process only every nth frame
if (!isThread1Frame())
return;
// ... break frame up into multiple image patches
// !!! PROBLEM: this call blocks thread2
vector<vector<float> > features = feature_engine->extractFeatures(patches);
// ... use features to compute output
frame_count++;
emit workFinished(output);
}
void Thread1Worker::initialize()
{
InitGoogleLogging("caffe-demo");
feature_engine = new FeatureEngine();
is_initialized = true;
}
bool Thread1Worker::isThread1Frame()
{
return frame_count % thread1_interval == 0;
}
void Thread2Worker::addThread1Result(OutputType output)
{
if (!is_initialized)
initialize();
thread1_output_queue.push(output);
thread1_count++;
processFrames();
}
void Thread2Worker::processFrames()
{
size_t num_process = (thread1_count * thread1_interval) - process_count;
size_t num_queue = thread2_images->size();
for (size_t i = 0; i < num_process && i < num_queue; i++)
{
Mat frame = thread2_images->get();
if (isThread1Frame()
{
curr_result = thread1_output_queue.front();
thread1_output_queue.pop();
}
else
{
curr_result = propagator->propagate(prev_result);
}
// update
prev_result = curr_result;
emit resultReady(curr_result);
}
}
void Thread2Worker::initialize()
{
propagator = new Propagator();
is_initialized = true;
}
bool Thread2Worker::isThread1Frame()
{
return process_count % thread1_interval == 0;
}
Thread1Worker::Thread1Worker()
{
thread1\u interval=10;//这是“n”
is_initialized=false;
}
空螺纹1工装::销钉(垫架)
{
如果(!已初始化)
初始化();
//仅每N帧处理一次
如果(!isThread1Frame())
返回;
//…将帧分解为多个图像块
//!!!问题:此调用阻止thread2
矢量特征=特征\引擎->提取特征(面片);
//…使用功能计算输出
帧计数++;
发出已完成的工作(输出);
}
void Thread1Worker::initialize()
{
InitGoogleLogging(“caffe演示”);
特征引擎=新特征引擎();
is_initialized=true;
}
bool Thread1Worker::isThread1Frame()
{
返回帧计数%thread1\u间隔==0;
}
thread2worker.cpp:
Thread1Worker::Thread1Worker()
{
thread1_interval = 10; // this is "n"
is_initialized = false;
}
void Thread1Worker::doWork(Mat frame)
{
if (!is_initialized)
initialize();
// process only every nth frame
if (!isThread1Frame())
return;
// ... break frame up into multiple image patches
// !!! PROBLEM: this call blocks thread2
vector<vector<float> > features = feature_engine->extractFeatures(patches);
// ... use features to compute output
frame_count++;
emit workFinished(output);
}
void Thread1Worker::initialize()
{
InitGoogleLogging("caffe-demo");
feature_engine = new FeatureEngine();
is_initialized = true;
}
bool Thread1Worker::isThread1Frame()
{
return frame_count % thread1_interval == 0;
}
void Thread2Worker::addThread1Result(OutputType output)
{
if (!is_initialized)
initialize();
thread1_output_queue.push(output);
thread1_count++;
processFrames();
}
void Thread2Worker::processFrames()
{
size_t num_process = (thread1_count * thread1_interval) - process_count;
size_t num_queue = thread2_images->size();
for (size_t i = 0; i < num_process && i < num_queue; i++)
{
Mat frame = thread2_images->get();
if (isThread1Frame()
{
curr_result = thread1_output_queue.front();
thread1_output_queue.pop();
}
else
{
curr_result = propagator->propagate(prev_result);
}
// update
prev_result = curr_result;
emit resultReady(curr_result);
}
}
void Thread2Worker::initialize()
{
propagator = new Propagator();
is_initialized = true;
}
bool Thread2Worker::isThread1Frame()
{
return process_count % thread1_interval == 0;
}
void Thread2Worker::addThread1Result(OutputType输出)
{
如果(!已初始化)
初始化();
线程1_输出_队列。推送(输出);
线程1_计数++;
processFrames();
}
void Thread2Worker::processFrames()
{
大小\u t num\u进程=(线程1\u计数*线程1\u间隔)-进程数;
size_t num_queue=thread2_images->size();
对于(大小i=0;iget();
if(isThread1Frame()
{
curr_result=thread1_output_queue.front();
thread1_output_queue.pop();
}
其他的
{
当前结果=传播者->传播(上一个结果);
}
//更新
上一次结果=当前结果;
发出结果(当前结果);
}
}
void Thread2Worker::initialize()
{
传播者=新的传播者();
is_initialized=true;
}
bool Thread2Worker::isThread1Frame()
{
返回进程计数%thread1\u间隔==0;
}
featureengine.cpp:
vector<vector<float> > FeatureEngine::extractFeatures(const vector<Mat>& images)
{
// setup Caffe network for feature extraction:
Blob<float>* input_layer = net->input_blobs()[0];
int num_images = images.size();
int height = input_geometry.height;
int width = input_geometry.width;
input_layer->Reshape(num_images, num_channels, height, width);
net->Reshape();
vector<Mat> input_channels;
wrapInputLayer(input_channels);
preprocess(images, &input_channels);
// !!! PROBLEM: this ~1s computation blocks thread2
// details: https://github.com/BVLC/caffe/blob/master/src/caffe/net.cpp#L594
net->ForwardPrefilled();
// copy Caffe network output to features vector
vector<vector<float> > features;
// ...
return features;
}
vector FeatureEngine::extractFeatures(常量向量和图像)
{
//为特征提取设置Caffe网络:
Blob*input_layer=net->input_blobs()[0];
int num_images=images.size();
int height=输入_几何体高度;
int width=输入_geometry.width;
输入\u层->重塑(num\u图像、num\u通道、高度、宽度);
net->重塑();
矢量输入信道;
wrapInputLayer(输入信道);
预处理(图像和输入通道);
//!!!问题:此~1s计算阻塞线程2
//详情:https://github.com/BVLC/caffe/blob/m