Sleeping in a Thread (C / POSIX Threads)

≯℡__Kan透↙ 提交于 2019-11-30 14:49:10

问题


I am developing a multithreaded application that makes use of POSIX Threads. I am using threads for doing a periodical job and for that purpose I am using usleep(3) to suspend thread execution. My question is how can I cancel usleep() timer from the main thread, I tried pthread_kill(thread, SIGALRM) but it has a global effect which results in termination of the main application (by default). Here is my pseudo code:

void threaded_task(void *ptr) {
    initialize();

    while(running) {
        do_the_work();
        usleep(some_interval);
    }

    clean_up();
    release_resources();
}

And here is the pseudo function that is used to stop (and gracefully shutdown) given thread from the main thread:

void stop_thread(pthread_t thread) {
    set_running_state(thread, 0); // Actually I use mutex staff
    // TODO: Cancel sleep timer so that I will not wait for nothing.
    // Wait for task to finish possibly running work and clean up 
    pthread_join(thread, NULL);
}

What is the convenient way to achieve my goal? Do I have to use conditional variables or can I do this using sleep() variants?


回答1:


USe select() with a FIFO or socket that you can poke in order to wake it up.




回答2:


You can also sleep with a semaphore (it's in fact their real purpose).

a sema_wait in your thread and a sema_post in your main thread. It's easy, it's clean, it's portable. Here a link to an article detailing the procedure: http://www.netrino.com/node/202




回答3:


The reason that SIGALRM is killing the entire application is that you probably haven't registered a signal handler for it. The default action for SIGALRM is for the kernel to terminate the process, so if usleep is implemented in a manner that does not use SIGALRM (using nanosleep or one of the polling functions with a timeout, for instance) then usleep would not have registered a handler or otherwise changed the default disposition of the signal.

void handle_alrm(int sig) {
}

...

int main(void) {
    signal(SIGALRM, handle_alrm);
    ...

should be enough to keep from killing your program, though you should look into the more complicated sigaction function rather than signal since it allows for more control and behaves more consistently across different platforms.

This is may cause problems if you then try to use the code on a system that does use SIGALRM to implement usleep or sleep, so you may want to just not use the standard library versions of those and use functions that have a more predictable implementation across all platforms (possibly a thin wrapper around nanosleep that provides the interface you want).




回答4:


We use a wait on a condition variable with a timeout using pthread_cond_timedwait

When we want to shutdown we set a 'shuting down' variable and do a pthread_cond_broadcast




回答5:


As an alternative to select, it is also possible to use pthread condition variables (see pthread_cond_init, pthread_cond_wait, and pthread_cond_signal), SysV semaphores, or POSIX semaphores. All of those are a better fit than usleep for an event-processing thread.




回答6:


It looks like you are running on Linux from the referenced man page. You should be able to use nanosleep and interupt with a application determined (SIGRTMIN+x) to the child process. Nanosleep has functionality to be interrupted by signals and return the remaining time it was supposed to have slept. You could also just use sleep if you are using larger periods of time to sleep.

nanosleep(2)

signal(7)

Any sort of IPC mentioned above could also help you solve this problem.

EDIT: It looks like you are already doing this except you should be using a signal that won't have an external effects on the program. Any of the sleep functions should be interrupted by a non blocked signal. The real-time signals are meant to be used on a per application basis.




回答7:


There's a number of ways to do this:

  • Use self-pipe trick @Ignacio mentions (Linux provides handy, but not portable, eventfd(2) to replace pipes here)
  • Connect threads via blocking queues built around mutexes and conditional variables, wait on empty queue, wakeup on item in the queue
  • Block signals in main thread before starting other threads, wait for signal, wake on signal - see pthread_sigmask(3)



回答8:


Maybe you need to mess with the signal mask or maybe signals can't get out of usleep...I don't know. I don know that could use sigwait() or sigtimedwait(). We use pthread_kill to wake threads, but we sleep them using sigwait....not usleep. This is the fastest way I have found to wake do this (40-50x faster than waiting on a pthread_cond according to my tests.)

We do this before creating threads:

int fSigSet;
sigemptyset(&fSigSet);
sigaddset(&fSigSet, SIGUSR1);
sigaddset(&fSigSet, SIGSEGV);
pthread_sigmask(SIG_BLOCK, &fSigSet, NULL);

Every thread created inherits this mask. I get a little confused with the masks. You are either telling the system to not do anything for certain signals or maybe you are telling the system that you are handling some signals...I don't know. Someone else can pipe in and help us out. If I new better how the masks worked, I might be able to tell you that you could just stick the above code in your ThreadProc. Also, I'm not sure if SIGSEGV is necessary.

Then a thread calls this to sleep itself:

int fSigReceived;
// next line sleeps the thread
sigwait(&fSigSet, &fSigReceived);  // assuming you saved fSigSet from above...
// you get here when the thread is woken up by the signal
// you can check fSigReceived if you care what signal you got.

Then you do this to wake a thread:

thread_kill(pThread, SIGUSR1);


来源:https://stackoverflow.com/questions/4016789/sleeping-in-a-thread-c-posix-threads

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!