Created
September 26, 2014 12:55
-
-
Save roxlu/1c1af99f92bafff9d8d9 to your computer and use it in GitHub Desktop.
Work in progress, simple cross platform mutex and threading code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 2.8.11) | |
set(bd ${CMAKE_CURRENT_LIST_DIR}) | |
set(id ${bd}) | |
include_directories(${id}) | |
add_executable(test_thread test_thread.cpp) | |
if (WIN32) | |
else() | |
target_link_libraries(test_thread pthread) | |
endif() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
d=${PWD} | |
if [ ! -d ${d}/build ] ; then | |
mkdir ${d}/build | |
fi | |
cd ${d}/build | |
cmake ../ | |
cmake --build . --config Release | |
if [ -d ${d}/build/Release ] ; then | |
cd ${d}/build/Release | |
./test_thread.exe | |
else | |
./test_thread | |
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <signal.h> | |
#if defined(__APPLE__) | |
# include <unistd.h> | |
#endif | |
/* ----------------------------------------------------------------------------------- */ | |
struct thread; /* forward declared */ | |
struct mutex; /* forward declared */ | |
typedef void*(*thread_function)(void* param); | |
thread* thread_alloc(thread_function func, void* param); | |
int thread_free(thread* t); | |
int thread_join(thread* t); | |
int mutex_init(mutex* m); | |
int mutex_destroy(mutex* m); | |
int mutex_lock(mutex* m); | |
int mutex_unlock(mutex* m); | |
/* ----------------------------------------------------------------------------------- */ | |
int thread_free(thread* t) { | |
if (NULL == t) { | |
return -1; | |
} | |
free(t); | |
return 0; | |
} | |
#if defined(_WIN32) | |
#define WIN32_LEAN_AND_MEAN | |
#include <windows.h> | |
struct thread { | |
HANDLE handle; | |
DWORD thread_id; | |
thread_function func; | |
void* user; | |
}; | |
struct mutex { | |
HANDLE handle; | |
}; | |
typedef struct thread; | |
typedef struct mutex; | |
DWORD WINAPI thread_wrapper_function(LPVOID param); | |
/* -- */ | |
DWORD WINAPI thread_wrapper_function(LPVOID param) { | |
thread* handle = (thread*)param; | |
if (NULL == handle) { return 0; } | |
if (NULL == handle->func) { return 0; } | |
handle->func(handle->user); | |
return 0; | |
} | |
thread* thread_alloc(thread_function func, void* param) { | |
thread* t = (thread*)malloc(sizeof(thread)); | |
if (NULL == t) { return NULL; } | |
if (NULL == func) { return NULL; } | |
t->user = param; | |
t->handle = CreateThread(NULL, 0, thread_wrapper_function, t, 0, &t->thread_id); | |
t->func = func; | |
if (NULL == t->handle) { | |
free(t); | |
t = NULL; | |
} | |
return t; | |
} | |
int thread_join(thread* t) { | |
if (NULL == t) { return -1; } | |
DWORD r = WaitForSingleObject(t->handle, INFINITE); | |
if (WAIT_OBJECT_0 == r) { return 0 ; } | |
else if (WAIT_ABANDONED == r) { return -2; } | |
else if (WAIT_FAILED) { return -3; } | |
return 0; | |
} | |
int mutex_init(mutex* m) { | |
if (NULL == m) { return -1; } | |
m->handle = CreateMutex(NULL, FALSE, NULL); /* default security, not owned by calling thread, unnamed. */ | |
if (NULL == m->handle) { return -2; } | |
return 0; | |
} | |
int mutex_destroy(mutex* m) { | |
if (NULL == m) { return -1; } | |
if (0 == CloseHandle(m->handle)) { return -2; } | |
return 0; | |
} | |
int mutex_lock(mutex* m) { | |
if (NULL == m) { return -1; } | |
DWORD r = WaitForSingleObject(m->handle, INFINITE); | |
if (WAIT_OBJECT_0 == r) { return 0 ; } | |
else if (WAIT_ABANDONED == r) { return -2; } | |
return 0; | |
} | |
int mutex_unlock(mutex* m) { | |
if (NULL == m) { return -1; } | |
if (!ReleaseMutex(m->handle)) { return -2; } | |
return 0; | |
} | |
#elif defined(__linux) or defined(__APPLE__) | |
# include <pthread.h> | |
struct thread { | |
pthread_t handle; | |
thread_function func; | |
void* user; | |
}; | |
struct mutex { | |
pthread_mutex_t handle; | |
}; | |
typedef struct thread thread; | |
typedef struct mutex mutex; | |
void* thread_function_wrapper(void* t); | |
/* --- */ | |
void* thread_function_wrapper(void* t) { | |
thread* handle = (thread*)t; | |
if (NULL == handle) { return NULL; } | |
handle->func(handle->user); | |
return NULL; | |
} | |
thread* thread_alloc(thread_function func, void* param) { | |
thread* t; | |
int r; | |
if (NULL == func) { return NULL; } | |
t = (thread*)malloc(sizeof(thread)); | |
if (!t) { return NULL; } | |
t->func = func; | |
t->user = param; | |
r = pthread_create(&t->handle, NULL, thread_function_wrapper, (void*)t); | |
if (0 != r) { | |
free(t); | |
t = NULL; | |
return NULL; | |
} | |
return t; | |
} | |
int mutex_init(mutex* m) { | |
if (NULL == m) { return -1; } | |
if (0 != pthread_mutex_init(&m->handle, NULL)) { return -2; } | |
return 0; | |
} | |
int mutex_destroy(mutex* m) { | |
if (NULL == m) { return -1; } | |
if (0 != pthread_mutex_destroy(&m->handle)) { return -2; } | |
return 0; | |
} | |
int mutex_lock(mutex* m) { | |
if (NULL == m) { return -1; } | |
if (0 != pthread_mutex_lock(&m->handle)) { return -2; } | |
return 0; | |
} | |
int mutex_unlock(mutex* m) { | |
if (NULL == m) { return -1; } | |
if (0 != pthread_mutex_unlock(&m->handle)) { return -2; } | |
return 0; | |
} | |
int thread_join(thread* t) { | |
if (NULL == t) { return -1; } | |
if (0 != pthread_join(t->handle, NULL)) { return -2; } | |
return 0; | |
} | |
#endif | |
/* -------------------------------------------------------------------------------- */ | |
static void* my_thread_function(void* p); | |
static void sigh(int s); | |
/* -------------------------------------------------------------------------------- */ | |
mutex my_mutex; | |
int shared_data = 0; | |
bool must_run = true; | |
int main() { | |
printf("\n\ntest_threading\n\n"); | |
signal(SIGINT, sigh); | |
/* Create a test thread. */ | |
thread* t = thread_alloc(my_thread_function, NULL); | |
if (NULL == t) { | |
printf("Cannot create thread.\n"); | |
exit(1); | |
} | |
/* create the mutex. */ | |
if (0 != mutex_init(&my_mutex)) { | |
printf("Cannot create mutex.\n"); | |
exit(1); | |
} | |
/* Loop a couple of times, join the thread. */ | |
int c = 0; | |
while (must_run) { | |
if (c % 10) { | |
printf("+ Count: %d\n", c); | |
} | |
if (3 == c) { | |
printf("+ Joining `my_thread_fuction`.\n"); | |
thread_join(t); | |
} | |
mutex_lock(&my_mutex); | |
printf("+ Shared data: %d\n", shared_data); | |
mutex_unlock(&my_mutex); | |
++c; | |
#if defined(__APPLE__) or defined(__linux) | |
usleep(1e6); | |
#elif defined(_WIN32) | |
Sleep(1e3); | |
#endif | |
} | |
thread_free(t); | |
t = NULL; | |
return 0; | |
} | |
/* -------------------------------------------------------------------------------- */ | |
static void sigh(int s) { | |
printf("Got signal.\n"); | |
must_run = false; | |
} | |
static void* my_thread_function(void* p) { | |
printf(">>My thread function!\n"); | |
int c = 0; | |
while (true) { | |
/* Change the shared data. */ | |
mutex_lock(&my_mutex); | |
shared_data++; | |
mutex_unlock(&my_mutex); | |
printf(">> My Thread Function Loop! Shared data: %d\n", shared_data); | |
#if defined(__APPLE__) or defined(__linux) | |
usleep(50e4); | |
#else defined(_WIN32) | |
Sleep(500); | |
#endif | |
c++; | |
if (c > 10) { | |
printf(">> My Thread Function will stop.\n"); | |
break; | |
} | |
} | |
printf(">> My Thread Function stopped.\n"); | |
return NULL; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment