需要在 C++ 中以周期性的时间间隔调用一个函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21057676/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
need to call a function at periodic time intervals in c++
提问by Execut1ve
I am writing a program in c++ where I need to call a function at periodic time intervals, say every 10ms or so. I've never done anything related to time or clocks in c++, is this a quick and easy problem or one of those where there is no neat solution?
我正在用 C++ 编写一个程序,我需要以周期性的时间间隔调用一个函数,比如每 10 毫秒左右。我从来没有做过任何与 C++ 中的时间或时钟相关的事情,这是一个快速而简单的问题还是一个没有巧妙解决方案的问题?
Thanks!
谢谢!
回答by user534498
A simple timer can be implemented as follows,
一个简单的定时器可以实现如下,
#include <iostream>
#include <chrono>
#include <thread>
#include <functional>
void timer_start(std::function<void(void)> func, unsigned int interval)
{
std::thread([func, interval]() {
while (true)
{
func();
std::this_thread::sleep_for(std::chrono::milliseconds(interval));
}
}).detach();
}
void do_something()
{
std::cout << "I am doing something" << std::endl;
}
int main() {
timer_start(do_something, 1000);
while(true);
}
This simple solution does not offer a way to stop the timer. The timer will keep running until the program exited.
这个简单的解决方案没有提供停止计时器的方法。计时器将一直运行,直到程序退出。
回答by florgeng
To complete the question, the code from @user534498 can be easily adapted to have the periodic tick interval.
It's just needed to determinate the next start time point at the beginning of the timer thread loop and sleep_until
that time point after executing the function.
为了完成这个问题,@user534498 的代码可以很容易地调整为具有周期性滴答间隔。只需要在定时器线程循环开始时和sleep_until
执行函数后确定下一个启动时间点即可。
#include <iostream>
#include <chrono>
#include <thread>
#include <functional>
void timer_start(std::function<void(void)> func, unsigned int interval)
{
std::thread([func, interval]()
{
while (true)
{
auto x = std::chrono::steady_clock::now() + std::chrono::milliseconds(interval);
func();
std::this_thread::sleep_until(x);
}
}).detach();
}
void do_something()
{
std::cout << "I am doing something" << std::endl;
}
int main()
{
timer_start(do_something, 1000);
while (true)
;
}
回答by user9335240
Sorry, but I didn't find a design simpler than that.
抱歉,我没有找到比这更简单的设计。
You could, make a class that owns both a thread, and a weak_ptr
to itself,
to be a "holder" that the callable can see it safely, because the callable
will still exists even if the object is destructed. You don't want a dangling pointer.
您可以将一个同时拥有线程和 a 的类weak_ptr
作为一个“持有者”,使可调用对象可以安全地看到它,因为即使对象被破坏,可调用对象仍然存在。你不想要一个悬空的指针。
template<typename T>
struct IntervalRepeater {
using CallableCopyable = T;
private:
weak_ptr<IntervalRepeater<CallableCopyable>> holder;
std::thread theThread;
IntervalRepeater(unsigned int interval,
CallableCopyable callable): callable(callable), interval(interval) {}
void thread() {
weak_ptr<IntervalRepeater<CallableCopyable>> holder = this->holder;
theThread = std::thread([holder](){
// Try to strongify the pointer, to make it survive this loop iteration,
// and ensure that this pointer is valid, if not valid, end the loop.
while (shared_ptr<IntervalRepeater<CallableCopyable>> ptr = holder.lock()) {
auto x = chrono::steady_clock::now() + chrono::milliseconds(ptr->interval);
ptr->callable();
this_thread::sleep_until(x);
}
});
}
public:
const CallableCopyable callable;
const unsigned int interval;
static shared_ptr<IntervalRepeater<T>> createIntervalRepeater(unsigned int interval,
CallableCopyable callable) {
std::shared_ptr<IntervalRepeater<CallableCopyable>> ret =
shared_ptr<IntervalRepeater<CallableCopyable>>(
new IntervalRepeater<CallableCopyable>(interval, callable));
ret->holder = ret;
ret->thread();
return ret;
}
~IntervalRepeater() {
// Detach the thread before it is released.
theThread.detach();
}
};
void beginItWaitThenDestruct() {
auto repeater = IntervalRepeater<function<void()>>::createIntervalRepeater(
1000, [](){ cout << "A second\n"; });
std::this_thread::sleep_for(std::chrono::milliseconds(3700));
}
int main() {
beginItWaitThenDestruct();
// Wait for another 2.5 seconds, to test whether there is still an effect of the object
// or no.
std::this_thread::sleep_for(std::chrono::milliseconds(2500));
return 0;
}
回答by Andreas Hadjigeorgiou
This is quite an old post but I found a really easy solution to this and I would like to share it:
这是一篇很老的帖子,但我找到了一个非常简单的解决方案,我想分享一下:
the solution is to
解决办法是
#include "unistd.h"
and use the function which is included in the above library,
并使用上述库中包含的函数,
usleep(int)
for example this would call a function every 3000 microseconds
例如,这将每 3000 微秒调用一个函数
int main() {
int sleep_time = 3000;
while(true) {
usleep(sleep_time);
call function;
}
return 0;
}
I used it as well for serial and parallel codes and works in both cases!
我也将它用于串行和并行代码,并且在两种情况下都可以使用!
回答by Ajay
It depends on what you would be doing on per interval - displaying time/ticker or something else at specific location of screen/form. Or you may need to send regular data to some connected machine (over socket or pipe). Do you really need 10 millisecond precision?
这取决于您将在每个时间间隔内执行的操作 - 在屏幕/表单的特定位置显示时间/自动收报机或其他内容。或者您可能需要将常规数据发送到某些连接的机器(通过套接字或管道)。你真的需要 10 毫秒的精度吗?
Depending on requirement, especially the precision requirement, you may have dedicated thread to do 'something', then wait and do same thing again. Or, on Windows, you may use SetTimer
that would trigger WM_TIMER
event on each interval (it wouldn't require thread). You may also use waitable timer, multimedia timer etc.
根据要求,尤其是精度要求,您可能有专用线程来做“某事”,然后等待并再次做同样的事情。或者,在 Windows 上,您可以使用SetTimer
它会WM_TIMER
在每个时间间隔触发事件(它不需要线程)。您还可以使用等待定时器、多媒体定时器等。
At last, but quite important - Do you need platform and compiler compatibility? Meaning that, which OS you would be using, or you need platform independent? What compiler features you are looking for (C++11, C++14 or pre C++11).
最后,但非常重要 - 您需要平台和编译器兼容性吗?这意味着,您将使用哪个操作系统,或者您需要独立于平台?您正在寻找哪些编译器功能(C++11、C++14 或 pre C++11)。
回答by RawBean
If you're coding with Visual C++, you could add a timer element to the form you want to call a periodic function (here it's called my form is MainForm
, and my timer MainTimer
). Add a call to the tick event in the "Events". The designer will add such line in your .h file:
如果您使用 Visual C++ 进行编码,则可以向要调用周期函数的表单添加一个计时器元素(此处称为 my form isMainForm
和 my timer MainTimer
)。在“事件”中添加对滴答事件的调用。设计器将在您的 .h 文件中添加这样的行:
this->MainTimer->Enabled = true;
this->MainTimer->Interval = 10;
this->MainTimer->Tick += gcnew System::EventHandler(this, &MainForm::MainTimer_Tick);
Then, at each interval (specified in ms), the application will call this function
然后,在每个时间间隔(以毫秒为单位),应用程序将调用此函数
private: System::Void MainTimer_Tick(System::Object^ sender, System::EventArgs^ e) {
/// Enter your periodic code there
}
回答by JMercer
You could look into threading:
你可以看看线程:
Here's a time interval controlled function implemented in C, using pthread.h, it should be a simple port to C++. Executing a function at specific intervals
这是一个用C实现的时间间隔控制函数,使用pthread.h,应该是C++的简单移植。 以特定时间间隔执行函数