static void *worker_thr_routine(void *data) { struct threadpool *pool = (struct threadpool*)data; struct threadpool_task *task; while (1) { task = threadpool_task_get_task(pool); if (task == NULL) { if (pool->stop_flag) { break; } else { DEMO_THREAD_Print("Warning an error has occurred when trying to obtain a worker task."); DEMO_THREAD_Print("The worker thread has exited."); break; } } if (task->routine_cb) { task->routine_cb(task->data); threadpool_task_init(task); if (pthread_mutex_lock(&(pool->free_tasks_mutex))) { perror("pthread_mutex_lock: "); DEMO_THREAD_Print("The worker thread has exited."); break; } if (threadpool_queue_enqueue(&(pool->free_tasks_queue),task)) { DEMO_THREAD_Print("Failed to enqueue a task to free tasks queue."); if (pthread_mutex_unlock(&(pool->free_tasks_mutex))) { perror("pthread_mutex_unlock: "); } DEMO_THREAD_Print("The worker thread has exited."); break; } if (threadpool_queue_getsize(&(pool->free_tasks_queue)) == 1) { if (pthread_cond_broadcast(&(pool->free_tasks_cond))) { perror("pthread_cond_broadcast: "); if (pthread_mutex_unlock(&(pool->free_tasks_mutex))) { perror("pthread_mutex_unlock: "); } break; } } if (pthread_mutex_unlock(&(pool->free_tasks_mutex))) { perror("pthread_mutex_unlock: "); DEMO_THREAD_Print("The worker thread has exited."); break; } } } return NULL; }
int threadpool_add_task(struct threadpool *pool, void (*routine)(void*), void *data, int blocking) { struct threadpool_task *task; if (pool == NULL) { REPORT_ERROR("The threadpool received as argument is NULL."); return -1; } if (pthread_mutex_lock(&(pool->free_tasks_mutex))) { perror("pthread_mutex_lock: "); return -1; } /* Check if the free task queue is empty. */ while (threadpool_queue_is_empty(&(pool->free_tasks_queue))) { if (!blocking) { /* Return immediately if the command is non blocking. */ if (pthread_mutex_unlock(&(pool->free_tasks_mutex))) { perror("pthread_mutex_unlock: "); return -1; } return -2; } /* blocking is set to 1, wait until free_tasks queue has a task to obtain. */ if (pthread_cond_wait(&(pool->free_tasks_cond),&(pool->free_tasks_mutex))) { perror("pthread_cond_wait: "); if (pthread_mutex_unlock(&(pool->free_tasks_mutex))) { perror("pthread_mutex_unlock: "); } return -1; } } /* Obtain an empty task. */ if ((task = (struct threadpool_task*)threadpool_queue_dequeue(&(pool->free_tasks_queue))) == NULL) { REPORT_ERROR("Failed to obtain an empty task from the free tasks queue."); if (pthread_mutex_unlock(&(pool->free_tasks_mutex))) { perror("pthread_mutex_unlock: "); } return -1; } if (pthread_mutex_unlock(&(pool->free_tasks_mutex))) { perror("pthread_mutex_unlock: "); return -1; } task->data = data; task->routine_cb = routine; /* Add the task, to the tasks queue. */ if (pthread_mutex_lock(&(pool->mutex))) { perror("pthread_mutex_lock: "); return -1; } if (threadpool_queue_enqueue(&(pool->tasks_queue),task)) { REPORT_ERROR("Failed to add a new task to the tasks queue."); if (pthread_mutex_unlock(&(pool->mutex))) { perror("pthread_mutex_unlock: "); } return -1; } if (threadpool_queue_getsize(&(pool->tasks_queue)) == 1) { /* Notify all worker threads that there are new jobs. */ if (pthread_cond_broadcast(&(pool->cond))) { perror("pthread_cond_broadcast: "); if (pthread_mutex_unlock(&(pool->mutex))) { perror("pthread_mutex_unlock: "); } return -1; } } if (pthread_mutex_unlock(&(pool->mutex))) { perror("pthread_mutex_unlock: "); return -1; } return 0; }
/** * This is the routine the worker threads do during their life. * * @param data Contains a pointer to the threadpool structure. * @return NULL. */ static void *worker_thr_routine(void *data) { struct threadpool *pool = (struct threadpool*)data; struct threadpool_task *task; while (1) { task = threadpool_task_get_task(pool); if (task == NULL) { if (pool->stop_flag) { /* Worker thr needs to exit (thread pool was shutdown). */ break; } else { /* An error has occurred. */ REPORT_ERROR("Warning an error has occurred when trying to obtain a worker task."); REPORT_ERROR("The worker thread has exited."); break; } } /* Execute routine (if any). */ if (task->routine_cb) { task->routine_cb(task->data); /* Release the task by returning it to the free_task_queue. */ threadpool_task_init(task); if (pthread_mutex_lock(&(pool->free_tasks_mutex))) { perror("pthread_mutex_lock: "); REPORT_ERROR("The worker thread has exited."); break; } if (threadpool_queue_enqueue(&(pool->free_tasks_queue),task)) { REPORT_ERROR("Failed to enqueue a task to free tasks queue."); if (pthread_mutex_unlock(&(pool->free_tasks_mutex))) { perror("pthread_mutex_unlock: "); } REPORT_ERROR("The worker thread has exited."); break; } if (threadpool_queue_getsize(&(pool->free_tasks_queue)) == 1) { /* Notify all waiting threads that new tasks can added. */ if (pthread_cond_broadcast(&(pool->free_tasks_cond))) { perror("pthread_cond_broadcast: "); if (pthread_mutex_unlock(&(pool->free_tasks_mutex))) { perror("pthread_mutex_unlock: "); } break; } } if (pthread_mutex_unlock(&(pool->free_tasks_mutex))) { perror("pthread_mutex_unlock: "); REPORT_ERROR("The worker thread has exited."); break; } } } return NULL; }