Question

I am writing a multithreaded server application which echoes back whatever client sends. I am spawning one thread per new client. I have used a while(1) loop to handle successive clients indefinitely (not exactly indefinite, I have forcefully limited it to 64, after which it rejects any new connection). Now I need to handle Ctrl+C signal in my server application.

One problem is that its not recommended to use signal() in multithreaded application.

However, even if I use it to catch the SIGINT signal (from Ctrl+C) using the method already discussed at SO this is what I need to do:
1) The server should no longer accept more clients.
2) The present connections to server should continue, except when client choses to disconnect.

My signal handler function is:

void Ctrl_C_handler(int sig)
{
    if(sig == SIGINT)       // Ctrl+C
    {
        printf("Ctrl+C detected by server !!\n");
        printf("No more connections will be accepted!!");
        pthread_cancel(main_thread_id);
    }
}

The methods I propose to use inside main() to cancel the thread are:

// Method 1
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
while(1)
{
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

            // ..
            // client handling
            // ..
}

// Method 2

while(1)
{   
    pthread_testcancel();       // Create Cancellation point
            // ..
            // client handling
            // ..
}

// Method 3

while(1)
{
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_testcancel();
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
            // ..
            // client handling
            // ..
}

Reason for why I am using pthread_cancel():

According to this link the thread will be finally terminated using pthread_exit() (Requirement 1 fulfilled). Since the NOTES section of pthread_exit() explains that it allows other threads to continue execution (Requirement 2 fulfilled).

Now if I am right till here,

Which method is best for cancellation of thread.
I chose method 3 because:

(Demerits) Method 1: Asynchronous thread cancel is not safe (as I saw in an answer in SO) if the thread allocates memory, and few other reasons

(Demerits) Method 2: According to this link there are so many other functions which can also work as cancellation points, some of those I will be using in my code.

(Merits) Method 3: Similar to method 2 but safer because other cancellation points will not be active since thread is cancel disabled.

Please tell me if my way is correct or not? And its wrong, is there any other better method to handle Ctrl+C similarly other than using pthread_cancel()?

Was it helpful?

Solution

I'd suggest avoiding cancellation.

Instead, register a SIGINT handler that close()s the server's listening socket. (Use sigaction for this.) The main thread can quit gracefully after the socket is closed, leaving any client threads running.

E.g. in pseudocode:

static int listen_fd = -1               // server socket

void handle_SIGINT(int s):              // Requirement 1
  if listen_fd >= 0:
    close(listen_fd)
    listen_fd = -1

int main(...):
  listen_fd = new_listening_socket(...)
  block_signal(SIGINT)
  trap_signal(SIGINT, handle_SIGINT)    // again, calls sigaction

  while 1:
    unblock_signal(SIGINT)
    new_client = accept(listen_fd)
    block_signal(SIGINT)

    if new_client < 0:                  // Requirement 1, also general error handling
      break

    spawn_worker_thread(new_client)     // probably attr PTHREAD_CREATE_DETACHED

  pthread_exit(NULL)                    // Requirement 2
  return 0                              // not reached

You can of course include more nuanced error handling, cleanup routines, etc., as needed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top