2011-11-05 13:35:31 +01:00
|
|
|
/**********************************
|
|
|
|
* @author Johan Hanssen Seferidis
|
|
|
|
* @date 12/08/2011
|
2014-12-29 11:51:52 +00:00
|
|
|
* License: MIT
|
2011-11-05 13:35:31 +01:00
|
|
|
*
|
|
|
|
**********************************/
|
|
|
|
|
|
|
|
/* 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
|
2014-12-29 11:53:37 +00:00
|
|
|
* the documentation found in the README.md file.
|
2011-11-05 13:35:31 +01:00
|
|
|
*
|
2014-12-29 11:53:37 +00:00
|
|
|
* In this header file a detailed overview of the functions and the threadpool's logical
|
|
|
|
* scheme is presented in case you wish to tweak or alter something.
|
2011-11-05 13:35:31 +01:00
|
|
|
*
|
|
|
|
*
|
2014-12-30 12:52:14 +00:00
|
|
|
*
|
|
|
|
* _______________________________________________________
|
2011-11-05 13:35:31 +01:00
|
|
|
* / \
|
|
|
|
* | JOB QUEUE | job1 | job2 | job3 | job4 | .. |
|
|
|
|
* | |
|
2014-12-29 11:55:29 +00:00
|
|
|
* | threadpool | thread1 | thread2 | .. |
|
2011-11-05 13:35:31 +01:00
|
|
|
* \_______________________________________________________/
|
|
|
|
*
|
2014-12-30 12:52:14 +00:00
|
|
|
*
|
2011-11-05 13:35:31 +01:00
|
|
|
* 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
|
2014-12-31 12:09:10 +00:00
|
|
|
* | | | rear ----------' |_job1_|
|
2011-11-05 13:35:31 +01:00
|
|
|
* | jobqueue----------------->| | |_job2_|
|
2014-12-31 12:09:10 +00:00
|
|
|
* | | | front ----------. |__..__|
|
2011-11-05 13:35:31 +01:00
|
|
|
* |___________| |___________| '----------->|_jobn_| Job for thread to take
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* job0________
|
|
|
|
* | |
|
|
|
|
* | function---->
|
|
|
|
* | |
|
|
|
|
* | arg------->
|
|
|
|
* | | job1________
|
|
|
|
* | next-------------->| |
|
|
|
|
* |___________| | |..
|
2014-12-31 12:09:10 +00:00
|
|
|
*
|
|
|
|
*
|
2011-11-05 13:35:31 +01:00
|
|
|
*/
|
|
|
|
|
2014-12-29 13:14:45 +00:00
|
|
|
|
2011-11-05 13:35:31 +01:00
|
|
|
#ifndef _THPOOL_
|
|
|
|
|
|
|
|
#define _THPOOL_
|
|
|
|
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <semaphore.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-12-30 12:56:19 +00:00
|
|
|
|
|
|
|
|
2014-12-29 11:51:52 +00:00
|
|
|
/* ========================== STRUCTURES ============================ */
|
2011-11-05 13:35:31 +01:00
|
|
|
|
|
|
|
|
2014-12-31 15:17:11 +00:00
|
|
|
/* Generic packed args */
|
|
|
|
typedef struct args_t {
|
|
|
|
void* arg1;
|
|
|
|
void* arg2;
|
|
|
|
} args_t;
|
|
|
|
|
|
|
|
|
2014-12-29 16:21:01 +00:00
|
|
|
/* Binary semaphore */
|
|
|
|
typedef struct bsem_t {
|
2014-12-30 12:28:21 +00:00
|
|
|
pthread_mutex_t mutex;
|
|
|
|
pthread_cond_t cond;
|
|
|
|
int v;
|
2014-12-29 16:21:01 +00:00
|
|
|
} bsem_t;
|
|
|
|
|
|
|
|
|
2014-12-29 13:14:45 +00:00
|
|
|
/* Job */
|
2014-11-23 11:38:34 +00:00
|
|
|
typedef struct job_t{
|
2014-12-30 12:28:21 +00:00
|
|
|
void* (*function)(void* arg); /* function pointer */
|
|
|
|
void* arg; /* function's argument */
|
|
|
|
struct job_t* prev; /* pointer to previous job */
|
2014-12-29 13:14:45 +00:00
|
|
|
} job_t;
|
2011-11-05 13:35:31 +01:00
|
|
|
|
|
|
|
|
2014-12-29 13:14:45 +00:00
|
|
|
/* Job queue */
|
2014-12-30 12:32:15 +00:00
|
|
|
typedef struct jobqueue_t{
|
2014-12-31 12:09:10 +00:00
|
|
|
job_t *front; /* pointer to front of queue */
|
|
|
|
job_t *rear; /* pointer to rear of queue */
|
2014-12-31 12:34:52 +00:00
|
|
|
bsem_t *has_jobs; /* flag as binary semaphore */
|
2014-12-30 12:28:21 +00:00
|
|
|
int len; /* number of jobs in queue */
|
2014-12-30 12:32:15 +00:00
|
|
|
} jobqueue_t;
|
2011-11-05 13:35:31 +01:00
|
|
|
|
|
|
|
|
2014-12-31 12:34:52 +00:00
|
|
|
/* Thread */
|
|
|
|
typedef struct thread_t{
|
2014-12-31 15:17:11 +00:00
|
|
|
int id; /* friendly id */
|
|
|
|
int working; /* is thread idle or working? */
|
2014-12-31 12:47:58 +00:00
|
|
|
pthread_t pthread; /* pointer to front of queue */
|
2014-12-31 12:34:52 +00:00
|
|
|
} thread_t;
|
|
|
|
|
|
|
|
|
2014-12-29 13:14:45 +00:00
|
|
|
/* Threadpool */
|
2011-11-05 13:35:31 +01:00
|
|
|
typedef struct thpool_t{
|
2014-12-30 12:28:21 +00:00
|
|
|
pthread_mutex_t rwmutex; /* used for queue w/r access */
|
2014-12-31 12:47:58 +00:00
|
|
|
thread_t* threads; /* pointer to threads */
|
2014-12-30 12:28:21 +00:00
|
|
|
int threadsN; /* amount of threads */
|
2014-12-31 12:34:52 +00:00
|
|
|
jobqueue_t* jobqueue; /* pointer to the job queue */
|
2014-12-29 13:14:45 +00:00
|
|
|
} thpool_t;
|
2011-11-05 13:35:31 +01:00
|
|
|
|
|
|
|
|
2014-12-30 12:52:14 +00:00
|
|
|
|
2014-12-30 12:56:19 +00:00
|
|
|
|
|
|
|
|
2014-12-29 11:51:52 +00:00
|
|
|
/* =========================== FUNCTIONS ============================ */
|
2011-11-05 13:35:31 +01:00
|
|
|
|
|
|
|
|
2014-12-29 11:51:52 +00:00
|
|
|
/* ---------------------- Threadpool specific ----------------------- */
|
2011-11-05 13:35:31 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @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
|
|
|
|
*/
|
2014-12-31 15:17:11 +00:00
|
|
|
static void thpool_thread_do(args_t* args);
|
2011-11-05 13:35:31 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @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
|
|
|
|
*/
|
2014-12-30 12:32:15 +00:00
|
|
|
int thpool_add_work(thpool_t* thpool, void *(*function_p)(void*), void* arg_p);
|
2011-11-05 13:35:31 +01:00
|
|
|
|
|
|
|
|
2014-12-29 16:42:27 +00:00
|
|
|
/**
|
|
|
|
* @brief Wait for all jobs in job queue to finish
|
|
|
|
*
|
|
|
|
* Will wait for all jobs in the queue to finish. Polling is used for this.
|
|
|
|
*
|
2014-12-30 12:52:14 +00:00
|
|
|
* @param threadpool to wait for
|
|
|
|
* @return nothing
|
2014-12-29 16:42:27 +00:00
|
|
|
*/
|
2014-12-30 12:32:15 +00:00
|
|
|
void thpool_wait(thpool_t* thpool);
|
2014-12-29 16:42:27 +00:00
|
|
|
|
|
|
|
|
2011-11-05 13:35:31 +01:00
|
|
|
/**
|
|
|
|
* @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
|
2014-12-30 12:52:14 +00:00
|
|
|
* @return nothing
|
2011-11-05 13:35:31 +01:00
|
|
|
*/
|
2014-12-30 12:32:15 +00:00
|
|
|
void thpool_destroy(thpool_t* thpool);
|
2011-11-05 13:35:31 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
2014-12-29 11:51:52 +00:00
|
|
|
/* ----------------------- Queue specific --------------------------- */
|
2011-11-05 13:35:31 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2014-12-29 11:51:52 +00:00
|
|
|
* @brief Initialize queue
|
2011-11-05 13:35:31 +01:00
|
|
|
* @param pointer to threadpool
|
|
|
|
* @return 0 on success,
|
|
|
|
* -1 on memory allocation error
|
|
|
|
*/
|
2014-12-30 12:32:15 +00:00
|
|
|
static int jobqueue_init(thpool_t* thpool);
|
2011-11-05 13:35:31 +01:00
|
|
|
|
|
|
|
|
2014-12-31 12:09:10 +00:00
|
|
|
/**
|
|
|
|
* @brief Clears the queue
|
|
|
|
* @param pointer to threadpool
|
|
|
|
* @return nothing
|
|
|
|
*/
|
|
|
|
static void jobqueue_clear(thpool_t* thpool);
|
|
|
|
|
|
|
|
|
2011-11-05 13:35:31 +01:00
|
|
|
/**
|
|
|
|
* @brief Add job to queue
|
|
|
|
*
|
|
|
|
* A new job will be added to the queue. The new job MUST be allocated
|
2014-11-23 11:38:34 +00:00
|
|
|
* before passed to this function or else other functions like jobqueue_empty()
|
2014-12-30 12:28:21 +00:00
|
|
|
* will be broken.
|
2011-11-05 13:35:31 +01:00
|
|
|
*
|
|
|
|
* @param pointer to threadpool
|
|
|
|
* @param pointer to the new job(MUST BE ALLOCATED)
|
|
|
|
* @return nothing
|
|
|
|
*/
|
2014-12-30 12:32:15 +00:00
|
|
|
static void jobqueue_push(thpool_t* thpool, job_t* newjob);
|
2014-11-23 11:38:34 +00:00
|
|
|
|
2011-11-05 13:35:31 +01:00
|
|
|
|
|
|
|
/**
|
2014-11-23 11:38:34 +00:00
|
|
|
* @brief Get first job from queue(removes it from queue)
|
2011-11-05 13:35:31 +01: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 11:38:34 +00:00
|
|
|
* @return point to job on success,
|
|
|
|
* NULL if there is no job in queue
|
2011-11-05 13:35:31 +01:00
|
|
|
*/
|
2014-12-30 12:32:15 +00:00
|
|
|
static job_t* jobqueue_pull(thpool_t* thpool);
|
2014-11-23 11:38:34 +00:00
|
|
|
|
2011-11-05 13:35:31 +01: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-12-31 12:09:10 +00:00
|
|
|
static void jobqueue_destroy(thpool_t* thpool);
|
2011-11-05 13:35:31 +01:00
|
|
|
|
|
|
|
|
2014-12-29 16:42:27 +00:00
|
|
|
/**
|
|
|
|
* Binary semaphore
|
|
|
|
*
|
2014-12-29 16:21:01 +00:00
|
|
|
* */
|
2014-12-29 16:42:27 +00:00
|
|
|
static void bsem_post(bsem_t *bsem);
|
|
|
|
static void bsem_wait(bsem_t *bsem);
|
2014-12-29 16:21:01 +00:00
|
|
|
|
|
|
|
|
2011-11-05 13:35:31 +01:00
|
|
|
#endif
|