diff --git a/.gitignore b/.gitignore index ab803f2..f3cdad8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,9 @@ *.a *.o *~ + +#ignore ide configs +.idea + +#ignore build directory +build diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..4efc143 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.4) +project(ThreadPool) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") + +find_package(Threads) + +include_directories(src) + +set(ParallelUtils src/threadpool.c src/threadpool.h) +add_executable(heavy tests/heavy.c ${ParallelUtils}) +target_link_libraries(heavy ${CMAKE_THREAD_LIBS_INIT}) + +add_executable(shutdown tests/shutdown.c ${ParallelUtils}) +target_link_libraries(shutdown ${CMAKE_THREAD_LIBS_INIT}) + +add_executable(thirdtest tests/thirdtest.c ${ParallelUtils}) +target_link_libraries(thirdtest ${CMAKE_THREAD_LIBS_INIT}) \ No newline at end of file diff --git a/Makefile b/Makefile index 2a05679..c4b2a11 100644 --- a/Makefile +++ b/Makefile @@ -6,16 +6,16 @@ CFLAGS += -g LDFLAGS += -g endif -TARGETS = tests/thrdtest tests/heavy tests/shutdown \ +TARGETS = tests/thirdtest tests/heavy tests/shutdown \ libthreadpool.so libthreadpool.a all: $(TARGETS) tests/shutdown: tests/shutdown.o src/threadpool.o -tests/thrdtest: tests/thrdtest.o src/threadpool.o +tests/thirdtest: tests/thirdtest.o src/threadpool.o tests/heavy: tests/heavy.o src/threadpool.o src/threadpool.o: src/threadpool.c src/threadpool.h -tests/thrdtest.o: tests/thrdtest.c src/threadpool.h +tests/thirdtest.o: tests/thirdtest.c src/threadpool.h tests/heavy.o: tests/heavy.c src/threadpool.h # Short-hand aliases @@ -36,6 +36,6 @@ clean: test: $(TARGETS) ./tests/shutdown - ./tests/thrdtest + ./tests/thirdtest ./tests/heavy diff --git a/README.md b/README.md index ccff328..994fbfe 100644 --- a/README.md +++ b/README.md @@ -22,3 +22,27 @@ some additional options: * Kill worker threads on destroy (hard, dangerous) * Support Windows API (medium) * Reduce locking contention (medium/hard) + +Update of Cmake Build Support +===================== +If your operating system installs [cmake](https://cmake.org/), then you could do as follows. + +- create a build dir, in current dir +```zsh +mkdir build +``` + +- enter into the build dir +```zsh +cd build +``` + +- then generate the makefile +```zsh +cmake .. +``` + +- then make in parallel +```zsh +make -j +``` diff --git a/src/threadpool.c b/src/threadpool.c index 1e0dab8..26e66f4 100644 --- a/src/threadpool.c +++ b/src/threadpool.c @@ -39,7 +39,7 @@ typedef enum { immediate_shutdown = 1, - graceful_shutdown = 2 + graceful_shutdown = 2 } threadpool_shutdown_t; /** @@ -52,6 +52,7 @@ typedef enum { typedef struct { void (*function)(void *); + void *argument; } threadpool_task_t; @@ -71,17 +72,17 @@ typedef struct { * @var started Number of started threads */ struct threadpool_t { - pthread_mutex_t lock; - pthread_cond_t notify; - pthread_t *threads; - threadpool_task_t *queue; - int thread_count; - int queue_size; - int head; - int tail; - int count; - int shutdown; - int started; + pthread_mutex_t lock; + pthread_cond_t notify; + pthread_t *threads; + threadpool_task_t *queue; + int thread_count; + int queue_size; + int head; + int tail; + int count; + int shutdown; + int started; }; /** @@ -93,17 +94,16 @@ static void *threadpool_thread(void *threadpool); int threadpool_free(threadpool_t *pool); -threadpool_t *threadpool_create(int thread_count, int queue_size, int flags) -{ - if(thread_count <= 0 || thread_count > MAX_THREADS || queue_size <= 0 || queue_size > MAX_QUEUE) { +threadpool_t *threadpool_create(int thread_count, int queue_size, int flags) { + if (thread_count <= 0 || thread_count > MAX_THREADS || queue_size <= 0 || queue_size > MAX_QUEUE) { return NULL; } - + threadpool_t *pool; int i; (void) flags; - if((pool = (threadpool_t *)malloc(sizeof(threadpool_t))) == NULL) { + if ((pool = (threadpool_t *) malloc(sizeof(threadpool_t))) == NULL) { goto err; } @@ -114,22 +114,22 @@ threadpool_t *threadpool_create(int thread_count, int queue_size, int flags) pool->shutdown = pool->started = 0; /* Allocate thread and task queue */ - pool->threads = (pthread_t *)malloc(sizeof(pthread_t) * thread_count); - pool->queue = (threadpool_task_t *)malloc - (sizeof(threadpool_task_t) * queue_size); + pool->threads = (pthread_t *) malloc(sizeof(pthread_t) * thread_count); + pool->queue = (threadpool_task_t *) malloc + (sizeof(threadpool_task_t) * queue_size); /* Initialize mutex and conditional variable first */ - if((pthread_mutex_init(&(pool->lock), NULL) != 0) || - (pthread_cond_init(&(pool->notify), NULL) != 0) || - (pool->threads == NULL) || - (pool->queue == NULL)) { + if ((pthread_mutex_init(&(pool->lock), NULL) != 0) || + (pthread_cond_init(&(pool->notify), NULL) != 0) || + (pool->threads == NULL) || + (pool->queue == NULL)) { goto err; } /* Start worker threads */ - for(i = 0; i < thread_count; i++) { - if(pthread_create(&(pool->threads[i]), NULL, - threadpool_thread, (void*)pool) != 0) { + for (i = 0; i < thread_count; i++) { + if (pthread_create(&(pool->threads[i]), NULL, + threadpool_thread, (void *) pool) != 0) { threadpool_destroy(pool, 0); return NULL; } @@ -139,25 +139,24 @@ threadpool_t *threadpool_create(int thread_count, int queue_size, int flags) return pool; - err: - if(pool) { + err: + if (pool) { threadpool_free(pool); } return NULL; } int threadpool_add(threadpool_t *pool, void (*function)(void *), - void *argument, int flags) -{ + void *argument, int flags) { int err = 0; int next; (void) flags; - if(pool == NULL || function == NULL) { + if (pool == NULL || function == NULL) { return threadpool_invalid; } - if(pthread_mutex_lock(&(pool->lock)) != 0) { + if (pthread_mutex_lock(&(pool->lock)) != 0) { return threadpool_lock_failure; } @@ -165,13 +164,13 @@ int threadpool_add(threadpool_t *pool, void (*function)(void *), do { /* Are we full ? */ - if(pool->count == pool->queue_size) { + if (pool->count == pool->queue_size) { err = threadpool_queue_full; break; } /* Are we shutting down ? */ - if(pool->shutdown) { + if (pool->shutdown) { err = threadpool_shutdown; break; } @@ -183,74 +182,72 @@ int threadpool_add(threadpool_t *pool, void (*function)(void *), pool->count += 1; /* pthread_cond_broadcast */ - if(pthread_cond_signal(&(pool->notify)) != 0) { + if (pthread_cond_signal(&(pool->notify)) != 0) { err = threadpool_lock_failure; break; } - } while(0); + } while (0); - if(pthread_mutex_unlock(&pool->lock) != 0) { + if (pthread_mutex_unlock(&pool->lock) != 0) { err = threadpool_lock_failure; } return err; } -int threadpool_destroy(threadpool_t *pool, int flags) -{ +int threadpool_destroy(threadpool_t *pool, int flags) { int i, err = 0; - if(pool == NULL) { + if (pool == NULL) { return threadpool_invalid; } - if(pthread_mutex_lock(&(pool->lock)) != 0) { + if (pthread_mutex_lock(&(pool->lock)) != 0) { return threadpool_lock_failure; } do { /* Already shutting down */ - if(pool->shutdown) { + if (pool->shutdown) { err = threadpool_shutdown; break; } pool->shutdown = (flags & threadpool_graceful) ? - graceful_shutdown : immediate_shutdown; + graceful_shutdown : immediate_shutdown; /* Wake up all worker threads */ - if((pthread_cond_broadcast(&(pool->notify)) != 0) || - (pthread_mutex_unlock(&(pool->lock)) != 0)) { + if ((pthread_cond_broadcast(&(pool->notify)) != 0) || + (pthread_mutex_unlock(&(pool->lock)) != 0)) { err = threadpool_lock_failure; break; } /* Join all worker thread */ - for(i = 0; i < pool->thread_count; i++) { - if(pthread_join(pool->threads[i], NULL) != 0) { + for (i = 0; i < pool->thread_count; i++) { + if (pthread_join(pool->threads[i], NULL) != 0) { err = threadpool_thread_failure; } } - } while(0); + } while (0); /* Only if everything went well do we deallocate the pool */ - if(!err) { + if (!err) { threadpool_free(pool); } return err; } -int threadpool_free(threadpool_t *pool) -{ - if(pool == NULL || pool->started > 0) { +int threadpool_free(threadpool_t *pool) { + if (pool == NULL || pool->started > 0) { return -1; } /* Did we manage to allocate ? */ - if(pool->threads) { + if (pool->threads) { free(pool->threads); free(pool->queue); - + /* Because we allocate pool->threads after initializing the mutex and condition variable, we're sure they're initialized. Let's lock the mutex just in case. */ @@ -258,29 +255,28 @@ int threadpool_free(threadpool_t *pool) pthread_mutex_destroy(&(pool->lock)); pthread_cond_destroy(&(pool->notify)); } - free(pool); + free(pool); return 0; } -static void *threadpool_thread(void *threadpool) -{ - threadpool_t *pool = (threadpool_t *)threadpool; +static void *threadpool_thread(void *threadpool) { + threadpool_t *pool = (threadpool_t *) threadpool; threadpool_task_t task; - for(;;) { + for (;;) { /* Lock must be taken to wait on conditional variable */ pthread_mutex_lock(&(pool->lock)); /* Wait on condition variable, check for spurious wakeups. When returning from pthread_cond_wait(), we own the lock. */ - while((pool->count == 0) && (!pool->shutdown)) { + while ((pool->count == 0) && (!pool->shutdown)) { pthread_cond_wait(&(pool->notify), &(pool->lock)); } - if((pool->shutdown == immediate_shutdown) || - ((pool->shutdown == graceful_shutdown) && - (pool->count == 0))) { + if ((pool->shutdown == immediate_shutdown) || + ((pool->shutdown == graceful_shutdown) && + (pool->count == 0))) { break; } @@ -301,5 +297,5 @@ static void *threadpool_thread(void *threadpool) pthread_mutex_unlock(&(pool->lock)); pthread_exit(NULL); - return(NULL); + return (NULL); } diff --git a/src/threadpool.h b/src/threadpool.h index 2f0ddbc..2123c7a 100644 --- a/src/threadpool.h +++ b/src/threadpool.h @@ -37,26 +37,26 @@ extern "C" { * @file threadpool.h * @brief Threadpool Header File */ - - /** - * Increase this constants at your own risk - * Large values might slow down your system - */ + +/** +* Increase this constants at your own risk +* Large values might slow down your system +*/ #define MAX_THREADS 64 #define MAX_QUEUE 65536 typedef struct threadpool_t threadpool_t; typedef enum { - threadpool_invalid = -1, - threadpool_lock_failure = -2, - threadpool_queue_full = -3, - threadpool_shutdown = -4, + threadpool_invalid = -1, + threadpool_lock_failure = -2, + threadpool_queue_full = -3, + threadpool_shutdown = -4, threadpool_thread_failure = -5 } threadpool_error_t; typedef enum { - threadpool_graceful = 1 + threadpool_graceful = 1 } threadpool_destroy_flags_t; /** diff --git a/tests/heavy.c b/tests/heavy.c index 936e0a6..935611d 100644 --- a/tests/heavy.c +++ b/tests/heavy.c @@ -23,10 +23,10 @@ pthread_mutex_t lock; int error; void dummy_task(void *arg) { - int *pi = (int *)arg; + int *pi = (int *) arg; *pi += 1; - if(*pi < QUEUES) { + if (*pi < QUEUES) { assert(threadpool_add(pool[*pi], &dummy_task, arg, 0) == 0); } else { pthread_mutex_lock(&lock); @@ -35,33 +35,32 @@ void dummy_task(void *arg) { } } -int main(int argc, char **argv) -{ +int main(int argc, char **argv) { int i, copy = 1; left = SIZE; pthread_mutex_init(&lock, NULL); - for(i = 0; i < QUEUES; i++) { + for (i = 0; i < QUEUES; i++) { pool[i] = threadpool_create(THREAD, SIZE, 0); assert(pool[i] != NULL); } usleep(10); - for(i = 0; i < SIZE; i++) { + for (i = 0; i < SIZE; i++) { tasks[i] = 0; assert(threadpool_add(pool[0], &dummy_task, &(tasks[i]), 0) == 0); } - while(copy > 0) { + while (copy > 0) { usleep(10); pthread_mutex_lock(&lock); copy = left; pthread_mutex_unlock(&lock); } - for(i = 0; i < QUEUES; i++) { + for (i = 0; i < QUEUES; i++) { assert(threadpool_destroy(pool[i], 0) == 0); } diff --git a/tests/shutdown.c b/tests/shutdown.c index b97c54c..f373cfe 100644 --- a/tests/shutdown.c +++ b/tests/shutdown.c @@ -21,8 +21,7 @@ void dummy_task(void *arg) { pthread_mutex_unlock(&lock); } -int main(int argc, char **argv) -{ +int main(int argc, char **argv) { int i; pthread_mutex_init(&lock, NULL); @@ -30,7 +29,7 @@ int main(int argc, char **argv) /* Testing immediate shutdown */ left = SIZE; pool = threadpool_create(THREAD, SIZE, 0); - for(i = 0; i < SIZE; i++) { + for (i = 0; i < SIZE; i++) { assert(threadpool_add(pool, &dummy_task, NULL, 0) == 0); } assert(threadpool_destroy(pool, 0) == 0); @@ -39,7 +38,7 @@ int main(int argc, char **argv) /* Testing graceful shutdown */ left = SIZE; pool = threadpool_create(THREAD, SIZE, 0); - for(i = 0; i < SIZE; i++) { + for (i = 0; i < SIZE; i++) { assert(threadpool_add(pool, &dummy_task, NULL, 0) == 0); } assert(threadpool_destroy(pool, threadpool_graceful) == 0); diff --git a/tests/thrdtest.c b/tests/thirdtest.c similarity index 86% rename from tests/thrdtest.c rename to tests/thirdtest.c index ec6cbd3..4f08af8 100644 --- a/tests/thrdtest.c +++ b/tests/thirdtest.c @@ -18,8 +18,7 @@ void dummy_task(void *arg) { pthread_mutex_unlock(&lock); } -int main(int argc, char **argv) -{ +int main(int argc, char **argv) { threadpool_t *pool; pthread_mutex_init(&lock, NULL); @@ -28,7 +27,7 @@ int main(int argc, char **argv) fprintf(stderr, "Pool started with %d threads and " "queue size of %d\n", THREAD, QUEUE); - while(threadpool_add(pool, &dummy_task, NULL, 0) == 0) { + while (threadpool_add(pool, &dummy_task, NULL, 0) == 0) { pthread_mutex_lock(&lock); tasks++; pthread_mutex_unlock(&lock); @@ -36,7 +35,7 @@ int main(int argc, char **argv) fprintf(stderr, "Added %d tasks\n", tasks); - while((tasks / 2) > done) { + while ((tasks / 2) > done) { usleep(10000); } assert(threadpool_destroy(pool, 0) == 0);