gpt4 book ai didi

c++ - 同时运行跟踪软件和服务器的正确方法是什么? (OpenCV 3)

转载 作者:行者123 更新时间:2023-11-28 05:33:15 24 4
gpt4 key购买 nike

我用 C++ 编写了一个在无限循环中运行的基本服务器。它接收来自客户端的信号来做事。我想要的主要过程是启动或停止我编写的一些跟踪软件。

我希望服务器在跟踪软件运行时仍然能够接收信号(例如,如果发出停止信号)。我认为最好的方法是为跟踪软件创建一个单独的线程,所以这就是我所做的:

void Server::tracking(Command c)
{
//I have since changed this method. The new implementation is below
//switch(c) {
// case START:
// player = VideoPlayer();
// player.setTrackStatus(true);
// t = std::thread(&Server::track, this);
// t.detach();
// break;
// case STOP:
// player.setTrackStatus(false);
// break;
// default:
// break;
//}
}

Server::track 只是调用 player.run()

VideoPlayer 是包含主跟踪循环的类。跟踪状态决定跟踪循环是否继续执行。

我第一次运行它时效果很好,它能够启动和停止跟踪。当我尝试在不重新启动服务器的情况下发送另一个“START”信号时,问题就出现了。

我已将问题缩小到 cv::namedWindow 函数。这是 VideoPlayer 类的开始:

void VideoPlayer::run(void)
{
//I have since changed this method. The new implementation is below
//initVC();
//openStream();
}

initVC() 是我创建 namedWindow 的地方,openStream 包含主跟踪循环。这是 initVC(我认为这是问题所在):

void VideoPlayer::initVC()
{
if(!capture.open("cut.mp4")) {
throw "Cannot open video stream";
}
std::cout << "flag 1" << std::endl;
cv::namedWindow("Tracker", CV_WINDOW_AUTOSIZE);
std::cout << "flag 2" << std::endl;
}

我发现在第二次运行时(即跟踪已经开始和停止并且服务器没有关闭和重新打开),flag 2 永远不会运行。我还发现,如果我省略 namedWindow,则程序会在 imshow() 之前停止。可能还值得注意的是,该程序并没有崩溃,它只是似乎暂停了。

我觉得我在线程方面做错了什么,因为我以前从未在 C++ 中使用过线程。

谢谢!

编辑: 我一直在尝试添加@Dom 建议的一些更改,但是我仍然遇到与之前类似的问题。我将在下面发布一些带有注释的附加代码以尝试解释。

服务器::跟踪:

这是为了根据从客户端收到的命令启动跟踪。

void Server::tracking(Command c)
{
switch(c) {
case START:
if(!isRunning) {
player = make_unique<VideoPlayer>();
isRunning = true;
player->setTrackStatus(isRunning);
}
else {
std::lock_guard<std::mutex> lock(mtx);
}
break;
case STOP:
if(isRunning) {
player->terminate();
player->exit(); //Destroys OpenCV stuff
player->joinThread();
player = nullptr;
isRunning = false;
}
else {
std::lock_guard<std::mutex> lock(mtx);
}
break;
default:
break;
}
}

VideoPlayer 构造函数:

VideoPlayer::VideoPlayer () : trackStatus(true)
{
tracker = Tracker(); //A separate class, related to the data from the tracked
//object. Not relevant to the current question
track_t = std::thread(&VideoPlayer::run, this);
return;
}

VideoPlayer::运行:

void VideoPlayer::run(void)
{
std::lock_guard<std::mutex> lock(mtx);
initVC(); //Initialises the OpenCV VideoCapture
openStream(); //Contains the main tracking code
return;
}

VideoPlayer::openStream:

void VideoPlayer::openStream() 
{
while(trackStatus) {
... //tracking stuff
}
return;
}

VideoPlayer::终止:

void VideoPlayer::terminate()
{
track = false;
std::lock_guard<std::mutex> lock(mtx);
}

VideoPlayer::joinThread:

void VideoPlayer::joinThread()
{
if(track_t.joinable()) {
std::cout << "flag 1" << std::endl;
track_t.join();
std::cout << "flag 2" << std::endl; //It fails here on my second "run"
return;
}
}

基本上,我的程序就在 track_t.join() 之前停止,这是我第二次运行跟踪(无需重新启动服务器)。 flag 1flag 2 打印我第一次运行跟踪。所有 OpenCV 组件似乎都已正确处理。如果我然后尝试再次打开跟踪,首先,跟踪似乎没有开始(但程序没有崩溃),然后如果我尝试停止跟踪,它会打印 flag 1 但随后无限期停止而不打印 flag 2

抱歉这篇文章太长了。我希望这能为我想要实现的目标提供更多背景信息

最佳答案

因此您的跟踪应用程序。可以实现如下:

#include <chrono>
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <memory>
#include <atomic>

enum Command : char
{
START = '1',
STOP = '0'
};

static std::mutex mtx; // mutex for I/O stream

class VideoPlayer
{
public:
VideoPlayer() : trackStatus()
{
initVC();
openStream();
};

~VideoPlayer()
{
closeStream();
uninitVC();
}

void setTrackStatus(bool status)
{
if (status && trackStatus == false)
{
trackStatus = status;
t = std::thread(&VideoPlayer::run, this);
}
else
{
trackStatus = false;
if (t.joinable())
{
t.join();
}
}
}


private:
void run()
{
tId = std::this_thread::get_id();
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "run thread: " << tId << std::endl;
}

while (trackStatus)
{
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "...running thread: " << tId << std::endl;
}
std::this_thread::sleep_for(std::chrono::seconds(1)); // encode chunk of stream and play, whatever....
}
}

void initVC()
{
/*
if (!capture.open("cut.mp4"))
{
throw "Cannot open video stream"; --> http://stackoverflow.com/questions/233127/how-can-i-propagate-exceptions-between-threads
}
std::cout << "flag 1" << std::endl;
//cv::namedWindow("Tracker", CV_WINDOW_AUTOSIZE);
//std::cout << "flag 2" << std::endl;
*/
}

void uninitVC()
{
}

void openStream()
{
}

void closeStream()
{
}

private:
std::atomic<bool> trackStatus; // atomic, because of access from another (main) thread
std::thread t; // thread for "tracking"
std::thread::id tId; // ID of the "tracking" thread
};


class Server
{
public:
Server() : isRunning(), player(std::make_unique<VideoPlayer>())
{
}

~Server() = default;

void tracking(Command c)
{
switch (c)
{
case START:
if (!isRunning)
{
isRunning = true;
player->setTrackStatus(isRunning);
}
else
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "Player is already running...\n";
}
break;
case STOP:
if (isRunning)
{
player->setTrackStatus(!isRunning);
isRunning = false;
}
else
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "Player is not running...\n";
}
break;
default:
break;
}
}

private:
std::unique_ptr<VideoPlayer> player;
bool isRunning;
};

int main()
{
std::cout << "main thread: " << std::this_thread::get_id() << std::endl;

Server srv;

char cmd = -1;
while (std::cin >> cmd)
{
switch (cmd)
{
case Command::START:
{
srv.tracking(Command::START);
}
break;
case Command::STOP:
{
srv.tracking(Command::STOP);
}
break;
default:
std::cout << "Unknown command...\n";
break;
}
}
}

您可以将线程的创建移动到 VideoPlayer 的构造函数并加入析构函数(我更喜欢...):

    VideoPlayer() : trackStatus(true)
{
initVC();
openStream();
t = std::thread(&VideoPlayer::run, this);
};

~VideoPlayer()
{
closeStream();
uninitVC();
if (t.joinable())
{
t.join();
}
}

但是需要一些修改来终止和清理线程,你可以使用类似的东西

public:
void VideoPlayer::terminate()
{
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "terminate thread: " << tId << std::endl;
}
trackStatus = false;
}

但是,在 START 期间创建播放器实例是必需的

player = std::make_unique<VideoPlayer>();

然后 Terminate() 并在 STOP 期间删除播放器

player->terminate();
player = nullptr;

希望,这对您有足够的启发;-)

关于c++ - 同时运行跟踪软件和服务器的正确方法是什么? (OpenCV 3),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38932120/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com