Thread Pool in C for web server Please review the following code for thread pool in C (I wrote it to implement a threaded web server for my personal project). I have been programming in C++ and Java but never did any serious programming in C.

threadpool.h

#ifndef THREAD_POOL_H
#define THREAD_POOL_H

#include &lt;pthread.h&gt;

#define MAX_THREAD 10

typedef struct {
    void *(*function) (void *);
} runnable_task;


typedef struct safe_queue_node {
    runnable_task *task;
    struct safe_queue_node *next;
} safe_queue_node;


typedef struct safe_queue{
    struct safe_queue_node *head;
    struct safe_queue_node *tail;
    pthread_mutex_t mutex;
} safe_queue;


typedef struct {
    pthread_t threads[MAX_THREAD];
    safe_queue *queue;
    int count;
    volatile int should_close;
} thread_pool;


runnable_task *
new_runnable_task(
        void *(*function) (void *));


thread_pool *
new_thread_pool();


void
free_thread_pool(
        thread_pool *pool);


void
add_task_to_pool(
        thread_pool *pool,
        runnable_task *task);


void
shutdown_thread_pool(
        thread_pool *pool);

#endif


threadpool.c

#include "threadpool.h"
#include &lt;stdlib.h&gt;

runnable_task *
new_runnable_task(
        void *(*function) (void *)) {
    runnable_task *task = malloc(sizeof(runnable_task));
    task-&gt;function = function;
    return task;
}


safe_queue_node *
_new_safe_queue_node(
        runnable_task *task) {
    safe_queue_node *node = malloc(sizeof(safe_queue_node));
    node-&gt;task = task;
    node-&gt;next = NULL;
    return node;
}


safe_queue *
_new_safe_queue() {
    safe_queue *queue = malloc(sizeof(safe_queue));
    pthread_mutex_init(&amp;queue-&gt;mutex, NULL);
    queue-&gt;head = NULL;
    queue-&gt;tail = NULL;
    return queue;
}


void
_free_safe_queue(
        safe_queue *queue) {
    free(queue);
}


runnable_task *
_get_from_queue(
        safe_queue *queue) {
    runnable_task *task = NULL;

    pthread_mutex_lock(&amp;queue-&gt;mutex);
    if (queue-&gt;head != NULL) {
        task = queue-&gt;head-&gt;task;
        queue-&gt;head = queue-&gt;head-&gt;next;
        if (queue-&gt;head == NULL)
            queue-&gt;tail = NULL;
    }
    pthread_mutex_unlock(&amp;queue-&gt;mutex);

    return task;
}


void *
_run_task(
        void *arg) {
    thread_pool *pool = (thread_pool *) arg;
    while (!pool-&gt;should_close) {
        runnable_task *task = _get_from_queue(pool-&gt;queue);
        if (task == NULL)
            continue;
        task-&gt;function(NULL);
    }

    return NULL;
}


thread_pool *
new_thread_pool(
        int count) {
    thread_pool *pool = malloc(sizeof(thread_pool));
    pool-&gt;queue = _new_safe_queue();
    pool-&gt;count = count &lt;= MAX_THREAD ? count : MAX_THREAD;
    pool-&gt;should_close = 0;
    for (int i = 0; i &lt; pool-&gt;count; i++) {
        pthread_create(pool-&gt;threads + i, NULL, _run_task, pool);
    }

    return pool;
}


void
free_thread_pool(
        thread_pool *pool) {
    _free_safe_queue(pool-&gt;queue);
    free(pool);
}


void
_add_to_queue(
        safe_queue *queue,
        runnable_task *task) {
    pthread_mutex_lock(&amp;queue-&gt;mutex);
    if (queue-&gt;head == NULL) {
        queue-&gt;head = queue-&gt;tail = _new_safe_queue_node(task);
    } else {
        queue-&gt;tail-&gt;next = _new_safe_queue_node(task);
        queue-&gt;tail = queue-&gt;tail-&gt;next;
    }
    pthread_mutex_unlock(&amp;queue-&gt;mutex);
}


void
add_task_to_pool(
        thread_pool *pool,
        runnable_task *task) {
    _add_to_queue(pool-&gt;queue, task);
}


void
shutdown_thread_pool(
        thread_pool *pool) {
    while (pool-&gt;queue-&gt;head != NULL) ;

    pool-&gt;should_close = 1;

    for (int i = 0; i &lt; pool-&gt;count; i++)
        pthread_join(pool-&gt;threads[i], NULL);
}
Busy waiting on an empty queue is doubleplusungood. Add a condition variable to the queue, let the threads to pthread_cond_wait on it, and pthread_cond_signal it when adding the task to the queue.
The functions you don't want to export (those with the leading underscores) shall be static.
sizeof(type) may lead to a double maintenance problem. Prefer sizeof(var), as in

thread_pool *pool = malloc(sizeof(*pool));