2

I used a thread pool, the main thread continuous add tasks into a queue, and throw a pthread_cond_signal that indicate the queue is not empty to the work threads. Then the work threads read the queue and throw a pthread_cond_signal indicate the queue is not full to the main thread. And when the program ran, I found the pthread_cond_wait is very slow, if I delete the pthread_cond_wait in function threadpool_add, it's much quicker, but I doubt it may has something wrong, How can I let the threadpool_add function faster? it's the performance bottleneck of my project, Here is the code:

/*
 * @function   int threadpool_add(threadpool_t *pool, void*(*function)(void *arg), void *arg, char* buf)
 * @desc       add tasks to the queue
 * @param      [thread_num] number of thread in pool,
 *             [queue_max_size] size of the queue for task
 */
int threadpool_add(threadpool_t *pool, void*(*function)(void *arg), void *arg)
{
    ulogd_log(ULOGD_NOTICE, "in threadpool_add\n");
    if(pool == NULL || function == NULL || arg == NULL)
    {
            return -1;
    }
    pthread_mutex_lock(&(pool->lock));
    /*
     * wait untill queue is not full
    */
    while ((pool->queue_size == pool->queue_max_size) && (!pool->shutdown))
    {
            pthread_cond_wait(&(pool->queue_not_full), &(pool->lock)); // if delete this, it's quicker
    }
    if (pool->shutdown)
    {
            pthread_mutex_unlock(&(pool->lock));
            return 0;
    }

    pool->task_queue[pool->queue_rear].function = function;
    pool->task_queue[pool->queue_rear].arg = arg;
    pool->queue_rear = (pool->queue_rear + 1)%pool->queue_max_size;
    pool->queue_size++;
    /*
     * notify to the threads, there has a task
     */
    pthread_cond_signal(&(pool->queue_not_empty));
    pthread_mutex_unlock(&(pool->lock));
    ulogd_log(ULOGD_NOTICE, "threadpool_add, tpool:0x%x, shutdown: %d, queue_size:%d, queue_not_empty:0x%x\n", pool, pool->shutdown, pool->queue_size, &(pool->queue_not_empty));
    return 0;
}

void *threadpool_thread(void *threadpool)
{
    threadpool_t *pool = (threadpool_t *)threadpool;
    threadpool_task_t task;
    while(1)
    {
            ulogd_log(ULOGD_NOTICE, "in thread 0x%x, tpool: 0x%x\n", pthread_self(), pool);
            /* Lock must be taken to wait on conditional variable */
            pthread_mutex_lock(&(pool->lock));
            while ((pool->queue_size == 0) && (!pool->shutdown))
            {
                    ulogd_log(ULOGD_NOTICE, "thread 0x%x is waiting, queue_size:%d, queue_not_empty:0x%x\n", pthread_self(), pool->queue_size, &(pool->queue_not_empty));
                    pthread_cond_wait(&(pool->queue_not_empty), &(pool->lock));
            }

            if (pool->shutdown)
            {
                    pthread_mutex_unlock(&(pool->lock));
                    ulogd_log(ULOGD_NOTICE,"thread 0x%x is exiting\n", pthread_self());
                    pthread_exit(NULL);
            }

            //get a task from queue
            task.function = pool->task_queue[pool->queue_front].function;
            task.arg = pool->task_queue[pool->queue_front].arg;
            pool->queue_front = (pool->queue_front + 1)%pool->queue_max_size;
            pool->queue_size--;
            //now queue must be not full
            pthread_mutex_unlock(&(pool->lock));
            pthread_cond_signal(&(pool->queue_not_full));

            // Get to work
            ulogd_log(ULOGD_NOTICE, "thread 0x%x start working\n", pthread_self());
            (*(task.function))(task.arg);
            // task run over
            ulogd_log(ULOGD_NOTICE, "thread 0x%x end working\n", pthread_self());
      }

      pthread_exit(NULL);
      return (NULL);
}
Spirit
  • 603
  • 2
  • 8
  • 16
  • You have the logs. What do they say? – n. m. could be an AI Jul 07 '14 at 08:39
  • I've fix the problem, but the performance bottleneck pop up, as I described above – Spirit Jul 07 '14 at 09:20
  • 2
    "*I found the pthread_cond_wait is very slow*" -- Can you describe precisely what you found that caused you to draw this conclusion? Also, is there more than one thread that might call `threadpool_add`? – David Schwartz Jul 07 '14 at 09:23
  • cause even I did not use the thread pool, the program ran faster, which means when I run the function "(*(task.function))(task.arg)" with out multithread, it's quicker than this(case my task.function will write data into file, and it's wrote more data than use threadpool). and you mean there may be another function called threadpool_add? If so, I think it will has error when compile – Spirit Jul 07 '14 at 09:28
  • I have tried your functions and they work great, speed up processing almost linearly with the number of threads, just like they should. Can you post a complete compilable program? – n. m. could be an AI Jul 07 '14 at 18:48
  • On windows using the equivalent functions I can confirm 15% performance loss compared to a bare bones spinlock. It might not be pthread_cond_wait() that introduces the slowness, it might be the OS itself yielding time. Increasing priority on the thread didn't help, cpu affinity also not. A simple spinlock is probably the best you can do, though also the "hottest" in terms of energy burnt on nothing. – John Jul 18 '23 at 20:58
  • I've found the same tendency on Linux. In my program 15 000 calls to `pthread_cond_wait` costs about 500 ms which is quite a lot. – Björn Lindqvist Aug 22 '23 at 11:49

0 Answers0