提问人:newww 提问时间:10/16/2023 更新时间:10/16/2023 访问量:72
创建异步计时器的新类后函数未返回
function is not returning after creating a new class of an asynchronous timer
问:
我有一个类正在创建一个应该在后台运行的异步计时器。我创建了一个计时器类,该类使用其单独的线程创建一个对象,并且应该在后台运行。最重要的是,我有两个函数 CreateTimer 和 DeleteTimer,它们将用于访问计时器类对象。我的目的是为多个线程调用 CreateTimer 和 DeleteTimer。我有以下代码:
#include <condition_variable>
#include <chrono>
#include <vector>
#include <algorithm>
#include <iostream>
#include <thread>
#include <atomic>
typedef struct
{
uint32_t msgId;
uint32_t param1;
uint32_t param2;
}THRD_EVENT_T;
enum THRD_EVENTID_T
{
THRD_MSGID_TIMER_FIRST,
THRD_STATEA,
THRD_STATEB,
THRD_STATEC,
THRD_MSGID_TIMER_LAST
};
std::mutex m;
void func_(THRD_EVENTID_T timerId_, int32_t pipeId_ )
{
std::cout<<"done\n";
}
class Timer
{
public:
Timer(THRD_EVENTID_T timerId, int32_t pipeId, uint32_t msPeriod)
: timerId_(timerId)
, pipeId_(pipeId)
, msPeriod_(msPeriod)
{
}
Timer(const Timer &obj) // copy constructor
{
timerId_ = obj.timerId_;
pipeId_ = obj.pipeId_;
msPeriod_ = obj.msPeriod_;
}
// Timer()
// {
// }
Timer() = delete;
Timer(Timer&&) = default;
~Timer()
{
if (thread_.joinable())
thread_.join();
}
void start()
{
std::cout<<"starting the timer\n";
thread_ = std::thread
{
[this]()
{
std::unique_lock<std::mutex> lck(mutex_);
cv_.wait_for(lck, msPeriod_, [this]() { return stop_waiting_.load(); });
if (not stop_waiting_)
func_(timerId_, pipeId_);
}
};
}
void stop()
{
stop_waiting_.store(true);
std::cout<<"Stopping the timer\n";
cv_.notify_one();
}
THRD_EVENTID_T GetTimerID()
{
return timerId_;
}
private:
std::chrono::milliseconds msPeriod_;
THRD_EVENTID_T timerId_;
int32_t pipeId_;
std::thread thread_;
std::condition_variable cv_;
std::mutex mutex_;
std::atomic<bool> stop_waiting_{false};
};
std::vector<Timer> tmrclass;
int32_t CreateTimer( const THRD_EVENTID_T timerId, const int32_t pipeId, const uint32_t msPeriod )
{
std::cout<<"Creating the timer\n";
std::unique_lock<std::mutex> lock(m);
Timer c (timerId, pipeId, msPeriod);
tmrclass.emplace_back(c);
c.start();
std::cout<<"exiting the createtimer function\n";
std::cout<<"returning....\n";
return 0;
}
int32_t Delete_Timer( const THRD_EVENTID_T timerId)
{
int32_t ret = -1;
std::cout<<"Deleting the timer function\n";
std::unique_lock<std::mutex> lock(m);
for (auto &f : tmrclass)
{
if(f.GetTimerID() == timerId)
{
std::cout<<"found the timer to delete\n";
f.stop();
break;
}
else
{
ret = -1;
}
}
return ret;
}
int main(int argc, const char *argv[])
{
THRD_EVENTID_T timerId;
timerId = THRD_STATEA;
int32_t pipeId = 0;
uint32_t msPeriod = 5000;
CreateTimer(timerId, pipeId, msPeriod);
std::cout<<"Have I exited the resource\n";
THRD_EVENTID_T timerId2;
timerId2 = THRD_STATEB;
int32_t pipeId2 = 1;
uint32_t msPeriod2 = 1000;
CreateTimer(timerId2, pipeId2, msPeriod2);
Delete_Timer(timerId);
return 0;
}
当我运行它时,代码没有从函数返回,它最终在打印出来后被卡住了,我无法弄清楚为什么它没有从函数返回CreateTimer
returning....
CreateTimer
答:
2赞
Some programmer dude
10/16/2023
#1
这是因为对象被破坏,它试图加入
线程。它将阻塞,直到线程完成。这会导致死锁,因为没有人告诉线程退出。c
对于真正独立的计时器,您需要分离线程。或者你需要使用一些其他的设计(单线程事件循环是常用的)。或者改用操作系统原生计时器。
评论
0赞
newww
10/16/2023
我究竟如何使用分离?在线程分离后,我是否需要跟踪线程?
1赞
Öö Tiib
10/16/2023
@newww问题是,您的“创建计时器”不仅会创建一个计时器,还会立即销毁它。这也许是你不希望它做的事情。在分离的被破坏对象上运行线程操作当然是非常糟糕的主意。
0赞
Some programmer dude
10/16/2023
@newww 这实际上比我最初想象的还要糟糕......在将对象添加到向量时,可以创建对象的副本,但保留对象中线程的所有权。线程不能被复制,只能被移动。您需要更多地考虑所有权,并将对象移动到向量所有。Timer
c
c
c
3赞
Some programmer dude
10/16/2023
@newww 您可以直接在矢量内创建计时器对象,而不是将计时器对象的所有权转让给向量。而不是你可以做.那么你根本不需要这个对象。我还建议您将复制构造函数标记为已删除,因为无法真正复制对象。tmrclass.emplace_back(c);
tmrclass.emplace_back(timerId, pipeId, msPeriod);
c
Timer
评论
Timer c
join()
Delete_Timer
CreateTimer