clinuxmultithreadingsignals

Using in C thrd_sleep() to either wait for time or interrupt by signal. Example?


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?


Solution

  • The question as posed

    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 the nanosleep() 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().

    Frame challenge

    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():

    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.