0

I am writing a simple client-server application using pthread-s API, which in pseudo code looks something like this:

static volatile sig_atomic_t g_running = 1;
static volatile sig_atomic_t g_threads = 0;
static pthread_mutex_t g_threads_mutex;

static void signalHandler(int signal)
{
  g_running = 0;
}

static void *threadServe(void *params)
{
  /* Increment the number of currently running threads. */
  pthread_mutex_lock(&g_threads_mutex);
  g_threads++;
  pthread_mutex_unlock(&g_threads_mutex);

  /* handle client's request */

  /* decrement the number of running threads */
  pthread_mutex_lock(&g_threads_mutex);
  g_threads--;
  pthread_mutex_unlock(&g_threads_mutex);
}


int main(int argc, char *argv[])
{
   /* do all the initialisation 
      (set up signal handlers, listening socket, ... ) */

   /* run the server loop */
   while (g_running)
   {
     int comm_sock = accept(listen_socket, NULL, 0);
     pthread_create(&thread_id, NULL, &threadServe, comm_sock) ;
     pthread_detach(thread_id);
   }

   /* wait for all threads that are yet busy processing client requests */
   while (1)
   {
     std::cerr << "Waiting for all threads to finish" << std::endl;;

     pthread_mutex_lock(&g_threads_mutex);
     if (g_threads <= 0)
     {
       pthread_mutex_unlock(&g_threads_mutex);
       break;
     }
     pthread_mutex_unlock(&g_threads_mutex);
   }

   /* clean up */
}

So the server is running in an infinite loop until a signal (SIGINT or SIGTERM) is received. The purpose of the second while loop is to let all the threads (that were processing client requests at the time a signal was received) to have a chance to finish the work they already started. However I don't like this design very much, because that second while loop is basically a busy loop wasting cpu resources.

I tried to search on Google for some good examples on threaded concurrent server, but I had no luck. An idea that came to my mind was to use pthread_cond_wait() istead of that loop, but I am not sure if this does not bring further problems.

So the question is, how to improve my design, or point me to a nice simple example that deals with similar problem as mine.

EDIT:

I was considering pthread_join(), but I din't know how to join with worker thread, while the main server loop (with accept() call in it) would be still running. If I called pthread_join() somewhere after pthread_create() (instead of pthread_detach()), then the while loop would be blocked until the worker thread is done and the whole threading would not make sense. I could use pthread_join() if I spawned all the threads at program start, but then I would have them around for the entire life of my server, which I thought might be a little inefficient. Also after reading man page I understood, that pthread_detach() is exactly suitable for this purpose.

4

1 に答える 1

1

The busy loop slurping CPU can easily be altered by having a usleep(10000); or something like that outside your mutex lock.

It would be more light-weight if you use a std::atomic<int> g_threads; - that way, you could get rid of the mutex altogether.

If you have an array of (active) thread_id's, you could just use a loop of

for(i = 0; i < num_active_threads; i++) 
   pthread_join(arr[i]);
于 2013-03-10T16:14:37.810 に答える