I want the main thread of my (Linux) program sleep for 5 minutes or until it receives a signal from a second thread.
The main thread should do a couple of things and then go to sleep. A separate thread listens to mqtt, and once it receives a message, it should wake the main thread (if currently sleeping).
As far as I got it, I can use thrd_sleep()
for this. It will return after the given amount of time or when a signal is received.
So am I right I just need the thrd_sleep()
call in my main? Or do I have to do something with a signal handler?
And how can I send a signal (and which?) from my listening thread to my main one?
What happens when listener sends the signal and the main thread is not sleeping? I need the signal to be ignored then.
Do you have some examples of how to implement such a thing?
You ask:
As far as I got it, I can use
thrd_sleep()
for this. It will return after the given amount of time or when a signal is received.
That's if you have thrd_sleep()
at all. You very well might not. If you don't want to deal with that uncertainty then nanosleep()
is a better bet. POSIX says:
The
thrd_sleep()
function is identical to thenanosleep()
function except that the return value may be any negative value when it fails with an error other than [EINTR].
You go on to ask:
So am I right I just need the
thrd_sleep()
call in my main? Or do I have to do something with a signal handler?
Do read the actual documentation for thrd_sleep()
, or whatever other function you consider using. That for thrd_sleep()
, linked above, says:
The
thrd_sleep()
function shall suspend execution of the calling thread until either the interval specified by duration has elapsed or a signal is delivered to the calling thread whose action is to invoke a signal-catching function or to terminate the process.
(Emphasis added.)
So yes, if you want to use thrd_sleep()
or nanosleep()
for your purpose then you do have to register a signal handler for the signal(s) you want to be able to wake the thread. The handler does not need to do anything at all, but if there isn't any then the signal will not break the sleep (unless by terminating the whole program).
And how can I send a signal (and which?) from my listening thread to my main one?
To send a signal (in this sense) to a specific thread, you would use the pthread_kill()
function. You will need the target thread's ID, which you can obtain by calling pthread_self()
in that thread.
What happens when listener sends the signal and the main thread is not sleeping?
The main thread is preempted to run the signal handler, whatever it does. This may or may not have additional effects, such as causing some system functions to fail with EINTR
, just like happens to thrd_sleep()
.
C signals are a clumsy tool. Some specific kinds of tasks require using them, but there are usually better alternatives.
In particular, the condition variable is the Swiss army knife of thread synchronization and coordination. A CV-based approach would be particularly well suited to your needs if the main thread is waiting so as to work with data produced by the other thread, but a CV could also serve a pure "wait until told to resume" scenario. Furthermore, Pthreads's flavor of CVs supports a timed wait operation that is nicely aligned with your desire for a time-limited wait.
Mirroring your questions about thrd_sleep()
:
Using a condition variable and pthread_cond_timedwait()
to perform the waiting does not require setting up a signal handler.
Your mqtt thread would notify the main thread to stop waiting by raising a flag of some sort, under protection of a mutex, and then calling pthread_cond_signal()
or pthread_cond_broadcast()
.
Nothing in particular happens if a CV is signaled when no thread is waiting on it. The event is not even recorded for later delivery.
Full details of how to correctly use CVs are a bit out of scope for this answer, but you can find many tutorials around the network, and there are many SO questions that address it. Do spend some time to learn how to do it correctly, for it's a little more involved than the simple sleep you asked about.