Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add-Cmake-Support #9

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@
*.a
*.o
*~

#ignore ide configs
.idea

#ignore build directory
build
17 changes: 17 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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})
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -36,6 +36,6 @@ clean:

test: $(TARGETS)
./tests/shutdown
./tests/thrdtest
./tests/thirdtest
./tests/heavy

24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
126 changes: 61 additions & 65 deletions src/threadpool.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

typedef enum {
immediate_shutdown = 1,
graceful_shutdown = 2
graceful_shutdown = 2
} threadpool_shutdown_t;

/**
Expand All @@ -52,6 +52,7 @@ typedef enum {

typedef struct {
void (*function)(void *);

void *argument;
} threadpool_task_t;

Expand All @@ -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;
};

/**
Expand All @@ -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;
}

Expand All @@ -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;
}
Expand All @@ -139,39 +139,38 @@ 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;
}

next = (pool->tail + 1) % pool->queue_size;

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;
}
Expand All @@ -183,104 +182,101 @@ 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. */
pthread_mutex_lock(&(pool->lock));
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;
}

Expand All @@ -301,5 +297,5 @@ static void *threadpool_thread(void *threadpool)

pthread_mutex_unlock(&(pool->lock));
pthread_exit(NULL);
return(NULL);
return (NULL);
}
Loading