Nov 15, 2018 at 5:00pm Nov 15, 2018 at 5:00pm UTC
Hello everyone!
I need to implement a multi platform timer.
I implemented it on Linux using 'timer_create' and 'timer_settime' calls, but I do not know which similar API calls Windows offers.
Do you know any Windows calls equivalent to Linux calls 'timer_create' and 'timer_settime'?
Thanks a lot!
Nov 15, 2018 at 5:09pm Nov 15, 2018 at 5:09pm UTC
Last edited on Nov 15, 2018 at 5:28pm Nov 15, 2018 at 5:28pm UTC
Nov 16, 2018 at 8:30am Nov 16, 2018 at 8:30am UTC
Hi Thomas thank you very much for your help! I will take a look.
It gets hard some times to find help on Windows platform (much easier on linux ;) )
Nov 16, 2018 at 10:13am Nov 16, 2018 at 10:13am UTC
Hi Thomas!
The problem with this approach is that the call 'GetMessage' blocks the application. If you take a look at the example of 'timer_create' here:
'
http://man7.org/linux/man-pages/man2/timer_create.2.html'
You will see that the main application has to sleep for a while (simulating a long time task), and then gets interrupted by a signal that is connected with the timer.
I need the same in Windows platform. Maybe I need a combination of Windows signals with timers...
Last edited on Nov 16, 2018 at 10:14am Nov 16, 2018 at 10:14am UTC
Nov 17, 2018 at 8:34am Nov 17, 2018 at 8:34am UTC
Somehow I don't understand the problem.
If you call the long time task as a function main will wait for it to finish and then continue with other tasks.
Nov 19, 2018 at 8:41am Nov 19, 2018 at 8:41am UTC
Hi Thomas, sorry my English is very bad.
This is an example of a Linux code of what I want:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#define INTERRUPT_TIME 3000000000 //Time(in nanoseconds) after which the main application will be interrupted
#define CLOCKID CLOCK_REALTIME
#define SIG SIGRTMIN
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
static void
handler(int sig, siginfo_t *si, void *uc)
{
(void ) si;
(void ) uc;
printf("Caught signal %d\n" , sig);
signal(sig, SIG_IGN);
}
int
main(int argc, char *argv[])
{
timer_t timerid;
struct sigevent sev;
struct itimerspec its;
long long freq_nanosecs;
struct sigaction sa;
/* Establish handler for timer signal */
printf("Establishing handler for signal %d\n" , SIG);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
if (sigaction(SIG, &sa, NULL) == -1)
errExit("sigaction" );
/* Create the timer */
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIG;
sev.sigev_value.sival_ptr = &timerid;
if (timer_create(CLOCKID, &sev, &timerid) == -1)
errExit("timer_create" );
/* Start the timer */
freq_nanosecs = (INTERRUPT_TIME);
its.it_value.tv_sec = freq_nanosecs / 1000000000;
its.it_value.tv_nsec = freq_nanosecs % 1000000000;
its.it_interval.tv_sec = 0;
its.it_interval.tv_nsec = 0;
if (timer_settime(timerid, 0, &its, NULL) == -1)
errExit("timer_settime" );
printf("Sleeping for 50 seconds\n" );
sleep(50); //a long running time task
exit(EXIT_SUCCESS);
}
You do not need to read the whole program. The long time task would be 'sleep(50);' which sleeps for 50 seconds. However, after 3 seconds the program gets interrupted and executes the callback 'handler'. If I call 'GetMessage', this call would block my application.
Last edited on Nov 19, 2018 at 8:42am Nov 19, 2018 at 8:42am UTC
Nov 19, 2018 at 3:10pm Nov 19, 2018 at 3:10pm UTC
I am sorry, I just realized I just need to pass 0 to the third parameter of 'SetWaitableTimer' so it is called only once.
Nov 19, 2018 at 5:07pm Nov 19, 2018 at 5:07pm UTC
Is there a reason why you can't use SleepEx?
I am not sure if a timer is actually the best solution.
What does this long running task do?
Report progress, error, finished....
BTW. What's your native language ?
Nov 20, 2018 at 9:45am Nov 20, 2018 at 9:45am UTC
The long running task is waiting for notifications in a condition variable. This is an example code that represents what my application has to do :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
#include <windows.h>
#include <iostream>
#include <chrono>
#include <thread>
#include <condition_variable>
#include <queue>
#include <atomic>
#include <mutex>
#define TIME_OUT 8000 //8 seconds
static std::queue<int > notifications;
static std::atomic<bool > stopSignal = false ;
static std::mutex mutexNotifications;
static MSG Msg;
static std::condition_variable cv;
static bool gotMessage = false ;
static bool messageFlag = false ;
VOID CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
{
(void )hWnd;
(void )nMsg;
std::cout << "Time: " << dwTime << '\n' ;
std::cout.flush();
}
static void run()
{
UINT TimerId = 0;
while (stopSignal.load() == false )
{
std::unique_lock<std::mutex> lock(mutexNotifications);
cv.wait(lock, []
{
if (messageFlag)
{
return (!notifications.empty() || stopSignal.load() == true || (gotMessage = GetMessage(&Msg, NULL, 0, 0)));
}
else
{
return (!notifications.empty() || stopSignal.load() == true );
}
});
if (gotMessage)
{
DispatchMessage(&Msg);
gotMessage = false ;
messageFlag = false ;
KillTimer(NULL, TimerId);
}
if (!notifications.empty())
{
int notification = notifications.front();
notifications.pop();
if (notification == 1)//start timer
{
messageFlag = true ;
std::cout << "Start timer" << std::endl;
TimerId = SetTimer(NULL, 0, TIME_OUT, (TIMERPROC)&TimerProc);
}
else
{
std::cout << "Got " << notification << std::endl;
}
}
}
}
int main(int argc, char *argv[], char *envp[])
{
std::thread runThread(run);
int input;
std::cout << "Start typing integers. 1 to start the timer and 0 to finish." << std::endl;
while (stopSignal.load() == false )
{
std::cin >> input;
mutexNotifications.lock();
if (input == 0)
{
stopSignal.exchange(true );
}
else
{
notifications.push(input);
}
cv.notify_one();
mutexNotifications.unlock();
}
runThread.join();
return 0;
}
You only need to execute this code. The application just reads integers (greater than 1) from stdin and shows them in stdout.
However, if you type 1, a timer is started with a delay of 8 seconds. During those 8 seconds, you cannot input any more values because the condition variable predicate is blocked in 'GetMessage'. So my problem is that the application stops processing notifications for 8 seconds.
My native language is Spanish. I know there are many C++ forums in Spanish, but I like this one. People here are always very kind and helpful (like you). Besides I am trying to improve my English as much as I can ;)
Last edited on Nov 20, 2018 at 9:52am Nov 20, 2018 at 9:52am UTC
Nov 21, 2018 at 7:48am Nov 21, 2018 at 7:48am UTC
Hi Thomas!
I read the PeekMessage documentation and it seems what I was looking for.
However, if I execute your code and type 1, the timer is not triggered... I will take a deeper look at this.
Thank you very much again!
Nov 23, 2018 at 1:01pm Nov 23, 2018 at 1:01pm UTC
I got a workaround using standard c++. My application has to process two kinds of notifications:
1. Immediate notifications (Notifications to be processed immediately).
2. Delayed notifications.
This is an example code :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
#include <iostream>
#include <atomic>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <chrono>
#define DELAYED_TIME 10000 //MILLISECONDS
class Notification
{
public :
Notification(std::queue<Notification*>* notificationsQueue)
: notificationsQueue_(notificationsQueue)
, isDelayed_(false )
{
}
/**
* @param delayMillisecons The delay in milliseconds. 0 if the notification is to be processed with no delay.
*/
void start(size_t delayMillisecons)
{
if (delayMillisecons > 0)
{
isDelayed_ = true ;
}
initialTime_ = std::chrono::duration_cast< std::chrono::milliseconds >(std::chrono::system_clock::now().time_since_epoch()).count() + delayMillisecons;
}
bool process()
{
size_t currentTime = std::chrono::duration_cast< std::chrono::milliseconds >(std::chrono::system_clock::now().time_since_epoch()).count();
if (currentTime >= initialTime_)
{
isDelayed_ ? std::cout << "Processed delayed event" << std::endl : std::cout << "Processed event" << std::endl;
;
return true ;
}
else
{
notificationsQueue_->push(this );
return false ;
}
}
private :
std::queue<Notification*>* notificationsQueue_;
size_t initialTime_;
bool isDelayed_;
};
static std::atomic<bool > endSignal;
static std::queue<Notification*> notificationsQueue;
static std::mutex mutexNotifications;
static std::condition_variable condNotification;
static void run()
{
//let's process notifications
while (endSignal.load() == false )
{
std::unique_lock<std::mutex> lock(mutexNotifications);
condNotification.wait(lock, []
{
return notificationsQueue.empty() == false || endSignal.load() == true ;
});
if (endSignal.load() == false )
{
Notification* notification = notificationsQueue.front();
notificationsQueue.pop();
if (notification->process())
{
delete notification;
}
}
}
}
int main()
{
endSignal = false ;
std::thread runThread(run);
int input;
Notification* notification = nullptr ;
printf("\n0 to quit.\n" );
printf("1 to push an immediate notification.\n" );
printf("2 to push a delayed notification(10 seconds).\n\n" );
while (endSignal.load() == false )
{
std::cin >> input;
mutexNotifications.lock();
switch (input)
{
case 0:
endSignal.exchange(true );
break ;
case 1:
notification = new Notification(¬ificationsQueue);
notification->start(0);
notificationsQueue.push(notification);
break ;
case 2:
notification = new Notification(¬ificationsQueue);
notification->start(DELAYED_TIME);
notificationsQueue.push(notification);
break ;
default :
std::cerr << "Invalid option" << std::endl;
}
condNotification.notify_all();
mutexNotifications.unlock();
}
runThread.join();
}
If you execute this code, now you can process immediate notifications while the delayed notifications are waiting to be processed.
The problem with this approach is that when you insert a delayed notification the CPU consume is 100% :(
I think I still have to investigate how to work with signals and timers in Windows.
Last edited on Nov 23, 2018 at 1:02pm Nov 23, 2018 at 1:02pm UTC
Nov 27, 2018 at 8:25am Nov 27, 2018 at 8:25am UTC
Hi JLBorges!
Thanks again for your response. Your proposal is good, but I need a solution without using threads, because that would mean to add synchronization mechanism that could be quite complex.
I have been investigation about timers in Windows, and it seems the application must be in an alertable state to be interrupted by the timer. It seems there is no way in Windows that the timer could interrupt my application in the middle of a long running task.
I still need more time to investigate this.
But thanks for your help!