2011-11-05 16:35:31 +04:00
|
|
|
/**********************************
|
|
|
|
* @author Johan Hanssen Seferidis
|
|
|
|
* @date 12/08/2011
|
|
|
|
* Last update: 01/11/2011
|
|
|
|
* License: LGPL
|
|
|
|
*
|
|
|
|
**********************************/
|
|
|
|
|
|
|
|
/* Description: Library providing a threading pool where you can add work on the fly. The number
|
|
|
|
* of threads in the pool is adjustable when creating the pool. In most cases
|
|
|
|
* this should equal the number of threads supported by your cpu.
|
|
|
|
*
|
|
|
|
* For an example on how to use the threadpool, check the main.c file or just read
|
|
|
|
* the documentation.
|
|
|
|
*
|
|
|
|
* In this header file a detailed overview of the functions and the threadpool logical
|
|
|
|
* scheme is present in case tweaking of the pool is needed.
|
|
|
|
* */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fast reminders:
|
|
|
|
*
|
|
|
|
* tp = threadpool
|
|
|
|
* thpool = threadpool
|
|
|
|
* thpool_t = threadpool type
|
|
|
|
* tp_p = threadpool pointer
|
|
|
|
* sem = semaphore
|
|
|
|
* xN = x can be any string. N stands for amount
|
|
|
|
*
|
|
|
|
* */
|
|
|
|
|
|
|
|
/* _______________________________________________________
|
|
|
|
* / \
|
|
|
|
* | JOB QUEUE | job1 | job2 | job3 | job4 | .. |
|
|
|
|
* | |
|
|
|
|
* | threadpool | thread1 | thread2 | .. |
|
|
|
|
* \_______________________________________________________/
|
|
|
|
*
|
|
|
|
* Description: Jobs are added to the job queue. Once a thread in the pool
|
|
|
|
* is idle, it is assigned with the first job from the queue(and
|
|
|
|
* erased from the queue). It's each thread's job to read from
|
|
|
|
* the queue serially(using lock) and executing each job
|
|
|
|
* until the queue is empty.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Scheme:
|
|
|
|
*
|
|
|
|
* thpool______ jobqueue____ ______
|
|
|
|
* | | | | .----------->|_job0_| Newly added job
|
|
|
|
* | | | head------------' |_job1_|
|
|
|
|
* | jobqueue----------------->| | |_job2_|
|
|
|
|
* | | | tail------------. |__..__|
|
|
|
|
* |___________| |___________| '----------->|_jobn_| Job for thread to take
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* job0________
|
|
|
|
* | |
|
|
|
|
* | function---->
|
|
|
|
* | |
|
|
|
|
* | arg------->
|
|
|
|
* | | job1________
|
|
|
|
* | next-------------->| |
|
|
|
|
* |___________| | |..
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _THPOOL_
|
|
|
|
|
|
|
|
#define _THPOOL_
|
|
|
|
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <semaphore.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ================================= STRUCTURES ================================================ */
|
|
|
|
|
|
|
|
|
|
|
|
/* Individual job */
|
2014-11-23 14:38:34 +03:00
|
|
|
typedef struct job_t{
|
|
|
|
void* (*function)(void* arg); /**< function pointer */
|
|
|
|
void* arg; /**< function's argument */
|
|
|
|
struct job_t* next; /**< pointer to next job */
|
|
|
|
struct job_t* prev; /**< pointer to previous job */
|
|
|
|
}job_t;
|
2011-11-05 16:35:31 +04:00
|
|
|
|
|
|
|
|
|
|
|
/* Job queue as doubly linked list */
|
|
|
|
typedef struct thpool_jobqueue{
|
2014-11-23 14:38:34 +03:00
|
|
|
job_t *head; /**< pointer to head of queue */
|
|
|
|
job_t *tail; /**< pointer to tail of queue */
|
2011-11-05 16:35:31 +04:00
|
|
|
}thpool_jobqueue;
|
|
|
|
|
|
|
|
|
|
|
|
/* The threadpool */
|
|
|
|
typedef struct thpool_t{
|
2014-11-23 14:38:34 +03:00
|
|
|
pthread_t* threads; /**< pointer to threads' ID */
|
|
|
|
int threadsN; /**< amount of threads */
|
|
|
|
thpool_jobqueue* jobqueue; /**< pointer to the job queue */
|
|
|
|
sem_t *queued_jobsN; /**< number of jobs in queue */
|
2011-11-05 16:35:31 +04:00
|
|
|
}thpool_t;
|
|
|
|
|
|
|
|
|
|
|
|
/* Container for all things that each thread is going to need */
|
|
|
|
typedef struct thread_data{
|
|
|
|
pthread_mutex_t *mutex_p;
|
|
|
|
thpool_t *tp_p;
|
|
|
|
}thread_data;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* =========================== FUNCTIONS ================================================ */
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------------------- Threadpool specific --------------------------- */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Initialize threadpool
|
|
|
|
*
|
|
|
|
* Allocates memory for the threadpool, jobqueue, semaphore and fixes
|
|
|
|
* pointers in jobqueue.
|
|
|
|
*
|
|
|
|
* @param number of threads to be used
|
|
|
|
* @return threadpool struct on success,
|
|
|
|
* NULL on error
|
|
|
|
*/
|
|
|
|
thpool_t* thpool_init(int threadsN);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief What each thread is doing
|
|
|
|
*
|
|
|
|
* In principle this is an endless loop. The only time this loop gets interuppted is once
|
|
|
|
* thpool_destroy() is invoked.
|
|
|
|
*
|
|
|
|
* @param threadpool to use
|
|
|
|
* @return nothing
|
|
|
|
*/
|
|
|
|
void thpool_thread_do(thpool_t* tp_p);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Add work to the job queue
|
|
|
|
*
|
|
|
|
* Takes an action and its argument and adds it to the threadpool's job queue.
|
|
|
|
* If you want to add to work a function with more than one arguments then
|
|
|
|
* a way to implement this is by passing a pointer to a structure.
|
|
|
|
*
|
|
|
|
* ATTENTION: You have to cast both the function and argument to not get warnings.
|
|
|
|
*
|
|
|
|
* @param threadpool to where the work will be added to
|
|
|
|
* @param function to add as work
|
|
|
|
* @param argument to the above function
|
|
|
|
* @return int
|
|
|
|
*/
|
|
|
|
int thpool_add_work(thpool_t* tp_p, void *(*function_p)(void*), void* arg_p);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Destroy the threadpool
|
|
|
|
*
|
|
|
|
* This will 'kill' the threadpool and free up memory. If threads are active when this
|
|
|
|
* is called, they will finish what they are doing and then they will get destroyied.
|
|
|
|
*
|
|
|
|
* @param threadpool a pointer to the threadpool structure you want to destroy
|
|
|
|
*/
|
|
|
|
void thpool_destroy(thpool_t* tp_p);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ------------------------- Queue specific ------------------------------ */
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Initialize queue
|
|
|
|
* @param pointer to threadpool
|
|
|
|
* @return 0 on success,
|
|
|
|
* -1 on memory allocation error
|
|
|
|
*/
|
2014-11-23 14:38:34 +03:00
|
|
|
int jobqueue_init(thpool_t* tp_p);
|
2011-11-05 16:35:31 +04:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Add job to queue
|
|
|
|
*
|
|
|
|
* A new job will be added to the queue. The new job MUST be allocated
|
2014-11-23 14:38:34 +03:00
|
|
|
* before passed to this function or else other functions like jobqueue_empty()
|
2011-11-05 16:35:31 +04:00
|
|
|
* will be broken.
|
|
|
|
*
|
|
|
|
* @param pointer to threadpool
|
|
|
|
* @param pointer to the new job(MUST BE ALLOCATED)
|
|
|
|
* @return nothing
|
|
|
|
*/
|
2014-11-23 14:38:34 +03:00
|
|
|
void jobqueue_push(thpool_t* tp_p, job_t* newjob_p);
|
|
|
|
|
2011-11-05 16:35:31 +04:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2014-11-23 14:38:34 +03:00
|
|
|
* @brief Get first job from queue(removes it from queue)
|
2011-11-05 16:35:31 +04:00
|
|
|
*
|
|
|
|
* This does not free allocated memory so be sure to have peeked() \n
|
|
|
|
* before invoking this as else there will result lost memory pointers.
|
|
|
|
*
|
|
|
|
* @param pointer to threadpool
|
2014-11-23 14:38:34 +03:00
|
|
|
* @return point to job on success,
|
|
|
|
* NULL if there is no job in queue
|
2011-11-05 16:35:31 +04:00
|
|
|
*/
|
2014-11-23 14:38:34 +03:00
|
|
|
job_t* jobqueue_pull(thpool_t* tp_p);
|
|
|
|
|
2011-11-05 16:35:31 +04:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get last job in queue (tail)
|
|
|
|
*
|
|
|
|
* Gets the last job that is inside the queue. This will work even if the queue
|
|
|
|
* is empty.
|
|
|
|
*
|
|
|
|
* @param pointer to threadpool structure
|
|
|
|
* @return job a pointer to the last job in queue,
|
|
|
|
* a pointer to NULL if the queue is empty
|
|
|
|
*/
|
2014-11-23 14:38:34 +03:00
|
|
|
job_t* thpool_jobqueue_peek(thpool_t* tp_p);
|
2011-11-05 16:35:31 +04:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Remove and deallocate all jobs in queue
|
|
|
|
*
|
|
|
|
* This function will deallocate all jobs in the queue and set the
|
|
|
|
* jobqueue to its initialization values, thus tail and head pointing
|
|
|
|
* to NULL and amount of jobs equal to 0.
|
|
|
|
*
|
|
|
|
* @param pointer to threadpool structure
|
|
|
|
* */
|
2014-11-23 14:38:34 +03:00
|
|
|
void jobqueue_empty(thpool_t* tp_p);
|
2011-11-05 16:35:31 +04:00
|
|
|
|
|
|
|
|
|
|
|
#endif
|