C-Thread-Pool/thpool.h

263 lines
7.3 KiB
C
Raw Normal View History

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;
/* Binary semaphore */
typedef struct bsem_t {
2014-12-30 12:28:21 +00:00
pthread_mutex_t mutex;
pthread_cond_t cond;
int v;
} 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? */
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 */
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:42:27 +00:00
static void bsem_post(bsem_t *bsem);
static void bsem_wait(bsem_t *bsem);
2011-11-05 13:35:31 +01:00
#endif