• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 297
  • Last Modified:

How to clean up a C program when terminated??

Hi there...

I am writing a C program on linux which I want to terminate gracefully. That is, I want to be able to close all running threads that may be active at the time the user does Ctrl C. My program listens for socket conenctions and create serperate threads to handle the connections it receives and do some processing while the main thread continues to listen for connections. How do I terminate all the threads, close all sockets..etc when the user ends the program either by closing the console or by pressing Ctrl C or Z?

engin32us
0
engin32us
Asked:
engin32us
  • 4
  • 4
2 Solutions
 
stefan73Commented:
Hi engin32us,
Actually, you don't need to. All open files and sockets are closed when a process terminates. But yes, it is a good practice.

For your graceful termination you need signal handling. A CTRL-C is a SIGINT, and closing a terminal sends a SIGHUP to your process.

Check man signal and man 6 signal for details. I'll give you a simple example.

Cheers,
Stefan
0
 
stefan73Commented:
engin32us,

Here you go:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

static void sighandler(int sig){
      printf("Caught signal %d, resetting signal handler\n",sig);
      signal(sig,sighandler);
}

int main(){
      /* Setup signal handler */
      signal(SIGHUP,sighandler);
      signal(SIGINT,sighandler);
      signal(SIGTERM,sighandler);

      /* sleep() is interrupted by a signal, so we loop here */
      while(1) {
            sleep(999);
            printf("Sleep woke up.\n");
      }
}

      

(you'll need to kill it with -9, as it's also capturing SIGTERM)

For a more complex application with multiple threads, it's usually best not to close them instantly, but to use a shutdown flag which is monitored regularly:

int shutdown=0;

[...]
while(!shutdown){
    do_something();
}

...your signal handler will set shutdown, so all threads shut down gracefully.

Stefan
0
 
sunnycoderCommented:
Hi engin32us,

The approach is the same as what stefan recommended ... catch the signal ...

However, I highly recommend that you use sigaction() interface instead of signal() interface ... Sigaction is lot more powerful, flexible and less error prone as compared to singal()

man sigaction

>How do I terminate all the threads, close all sockets..etc
to kill the threads use pthread_kill ()

man pthread_kill

You will have all the socket ids in the main thread (it accepts the connections) ... You need to maintain a list of them (the active/open sockets) and during cleanup you can traverse that list and close all the open sockets ...

Alternatively you can register all the cleanup activity using the atexit() function

man atexit

The functions registered using atexit() will be called when the process is about to exit so you save the signal handling efforts ... However signal handling is more graceful and offers you better control

If you need more information, post back :o)


cheers
sunnycoder
0
Restore individual SQL databases with ease

Veeam Explorer for Microsoft SQL Server delivers an easy-to-use, wizard-driven interface for restoring your databases from a backup. No expert SQL background required. Web interface provides a complete view of all available SQL databases to simplify the recovery of lost database

 
stefan73Commented:
sunnycoder,
> use sigaction() interface instead of signal() interface

Good point. I guess I was too lazy for using sigaction() :-)

Stefan
0
 
oumerCommented:
I have had several problems when using signals and threads. The best way I found is to just exit with the signal handler and do my cleanup with some function that I had registed at the beginning of my code. Also, I will mask the signal from all the threads except the one that I want to catch the signal, cause sometimes that also causes a problem. Example program will follow in a momment ......
0
 
oumerCommented:
The skeleton code of how I would do is like this ....



bool exited = false;

void bye()
{
//I use the exited variable, cause I have sometimes encounterd bye being called more than once incase I press ctrl+c again while we are in bye

   if(!exited)
      exited=true;
   else
       return;

  //do you cleanup of threads and objects here

}

void signal_handler( int sig)
{
   printf("hmm, you don't like me anymore?\n");
   exit(0);  //atexit will be called at this point
}

void * thread_1(void *arg)
{
//thread_1's body

}

void * thread_2(void *arg)
{
//thread_1's body

}

int main()
{
sigset_t set;
struct sigaction sa;

atexit(bye);

//These three lines will mask the SIGINT from being catched by the child threads
sigemptyset(&set);
sigaddset(&set,SIGINT);
pthread_sigmask(SIG_BLOCK, &set, NULL);

pthread_create(&th1, NULL, thread_1, NULL);
pthread_create(&th2, NULL, thread_2, NULL);

//now the threads are created, you can unmask the SIGINT now, making sure only the parent thread wil catch the signal
pthread_sigmask(SIG_BLOCK, &set, NULL);
sa.sa_handler=signal_handler;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);

//here you can wait for the two threads to finsih or do whatever you want to do
//just make sure you do something so that control doesn't reach to the end of the main function ....

}
0
 
stefan73Commented:
oumer,
I wonder how Linux does the signal handling within a multi-threaded process when each thread has his own pid...

Any ideas?

Stefan
0
 
oumerCommented:
Hi Stefan,
>I wonder how Linux does the signal handling within a multi-threaded process when each thread has his own pid...
I dont get it when you say "when each thread has his own pid ..."
0
 
oumerCommented:
Let's say you have a signal handler for some signals like SIG_FPE, SIG_SEGV, and SIG_INT

In the case of floating point ad segmentaion errors, the signals are sent to the concerned thread, the one that has caused the exception to happen. So if the signal handler was shared between the threads (i.e. you didn't mask the signals), it will be called from the concerned thread.

On the case asynchronous signals like sig_int when you press ctrl+c, there is no guarantee from which thread the signal handler will be called.
0

Featured Post

Get free NFR key for Veeam Availability Suite 9.5

Veeam is happy to provide a free NFR license (1 year, 2 sockets) to all certified IT Pros. The license allows for the non-production use of Veeam Availability Suite v9.5 in your home lab, without any feature limitations. It works for both VMware and Hyper-V environments

  • 4
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now