├── .gitmodules ├── CMakeLists.txt ├── JniAtomiThreadPool_Linux_Mac ├── build_linux.sh └── build_mac.sh ├── JniAtomiThreadPool_VS ├── JniAtomiThreadPool_VS.sln ├── JniAtomiThreadPool_VS.vcxproj └── JniAtomiThreadPool_VS.vcxproj.filters ├── LICENSE ├── README.md ├── at_thpool.c ├── at_thpool.h ├── cmake_uninstall.cmake.in ├── java_source ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── taymindis │ │ │ ├── AtomicThreadPool.java │ │ │ ├── AtomicThreadPoolTask.java │ │ │ └── NativeUtils.java │ └── resources │ │ ├── VS32.dll │ │ ├── VS32_full.dll │ │ ├── VS64.dll │ │ ├── VS64_full.dll │ │ └── libatpool_jni.so │ └── test │ └── java │ └── com │ └── github │ └── taymindis │ └── test │ ├── MyTask.java │ └── Test1.java ├── jni-cross-platform ├── AtomicThreadPool.c └── AtomicThreadPool.h └── threadpool_example.c /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lfqueue"] 2 | path = lfqueue 3 | url = https://github.com/Taymindis/lfqueue.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project(athpool) 3 | 4 | set(PROJNAME athpool) 5 | 6 | IF (WIN32 OR MSVC OR MSYS OR MINGW OR APPLE) 7 | message( FATAL_ERROR "for windows build, please open with visual studio project") 8 | endif() 9 | 10 | MESSAGE(STATUS "Unix Build ... ") 11 | 12 | IF (NOT DEFINED CMAKE_INSTALL_INCLUDEDIR) 13 | SET(CMAKE_INSTALL_INCLUDEDIR /usr/local/include) 14 | ENDIF(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR) 15 | 16 | include_directories(/usr/local/include /usr/include lfqueue) 17 | 18 | file(GLOB_RECURSE sources at_thpool.h at_thpool.c lfqueue/lfqueue.h lfqueue/lfqueue.c) 19 | file(GLOB_RECURSE example_test ${sources} threadpool_example.c) 20 | 21 | add_executable(example_threadpool ${example_test}) 22 | target_link_libraries(example_threadpool PUBLIC pthread) 23 | 24 | 25 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wall -Wstrict-prototypes -Wmissing-prototypes") 26 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-declarations -Wshadow -Wpointer-arith -Wcast-qual") 27 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wsign-compare -pedantic") 28 | 29 | ############################################################################### 30 | ## packaging ################################################################## 31 | ############################################################################### 32 | add_library(${PROJNAME}.static STATIC ${sources}) 33 | target_link_libraries(${PROJNAME}.static pthread) 34 | set_target_properties(${PROJNAME}.static PROPERTIES OUTPUT_NAME ${PROJNAME}) 35 | add_library(${PROJNAME} SHARED ${sources}) 36 | target_link_libraries(${PROJNAME} pthread) 37 | 38 | 39 | # link_directories(/usr/local/lib /usr/lib) 40 | 41 | ## For .a library 42 | install(TARGETS ${PROJNAME}.static EXPORT ${PROJNAME} 43 | ARCHIVE DESTINATION lib${LIB_SUFFIX} 44 | LIBRARY DESTINATION lib${LIB_SUFFIX} 45 | # RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 46 | ) 47 | 48 | ## For .so library 49 | install(TARGETS ${PROJNAME} EXPORT ${PROJNAME} 50 | ARCHIVE DESTINATION lib${LIB_SUFFIX} 51 | LIBRARY DESTINATION lib${LIB_SUFFIX} 52 | # RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 53 | ) 54 | install(FILES at_thpool.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 55 | 56 | install(CODE "execute_process(COMMAND ldconfig)") 57 | 58 | 59 | configure_file( 60 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" 61 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" 62 | IMMEDIATE @ONLY) 63 | 64 | add_custom_target(uninstall 65 | COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) 66 | 67 | 68 | set(CPACK_PACKAGE_NAME "at_thpool") 69 | set(CPACK_PACKAGE_VERSION "1.0.0") 70 | 71 | # we don't want to split our program up into several things 72 | set(CPACK_MONOLITHIC_INSTALL 1) 73 | 74 | # This must be last 75 | include(CPack) 76 | -------------------------------------------------------------------------------- /JniAtomiThreadPool_Linux_Mac/build_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | gcc -shared -o libatpool_jni.so -fPIC -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -I$JAVAHOME/include/darwin -I/usr/local/include -I/usr/include -I../ -I../lfqueue -I../jni-cross-platform ../lfqueue/lfqueue.c ../at_thpool.c ../jni-cross-platform/AtomicThreadPool.c -pthread 4 | -------------------------------------------------------------------------------- /JniAtomiThreadPool_Linux_Mac/build_mac.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | clang -dynamiclib -O3 -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -I$JAVAHOME/include/darwin -I/usr/local/include -I/usr/include -I../ -I../lfqueue -I../jni-cross-platform ../lfqueue/lfqueue.c ../at_thpool.c ../jni-cross-platform/AtomicThreadPool.c -o libatpool_jni.dylib 5 | -------------------------------------------------------------------------------- /JniAtomiThreadPool_VS/JniAtomiThreadPool_VS.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2042 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JniAtomiThreadPool_VS", "JniAtomiThreadPool_VS.vcxproj", "{50C8DCEE-CAFF-42E0-9B3B-9A8E76FF7D9D}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | FullPackMT|x64 = FullPackMT|x64 13 | FullPackMT|x86 = FullPackMT|x86 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {50C8DCEE-CAFF-42E0-9B3B-9A8E76FF7D9D}.Debug|x64.ActiveCfg = Debug|x64 19 | {50C8DCEE-CAFF-42E0-9B3B-9A8E76FF7D9D}.Debug|x64.Build.0 = Debug|x64 20 | {50C8DCEE-CAFF-42E0-9B3B-9A8E76FF7D9D}.Debug|x86.ActiveCfg = Debug|Win32 21 | {50C8DCEE-CAFF-42E0-9B3B-9A8E76FF7D9D}.Debug|x86.Build.0 = Debug|Win32 22 | {50C8DCEE-CAFF-42E0-9B3B-9A8E76FF7D9D}.FullPackMT|x64.ActiveCfg = FullPackMT|x64 23 | {50C8DCEE-CAFF-42E0-9B3B-9A8E76FF7D9D}.FullPackMT|x64.Build.0 = FullPackMT|x64 24 | {50C8DCEE-CAFF-42E0-9B3B-9A8E76FF7D9D}.FullPackMT|x86.ActiveCfg = FullPackMT|Win32 25 | {50C8DCEE-CAFF-42E0-9B3B-9A8E76FF7D9D}.FullPackMT|x86.Build.0 = FullPackMT|Win32 26 | {50C8DCEE-CAFF-42E0-9B3B-9A8E76FF7D9D}.Release|x64.ActiveCfg = Release|x64 27 | {50C8DCEE-CAFF-42E0-9B3B-9A8E76FF7D9D}.Release|x64.Build.0 = Release|x64 28 | {50C8DCEE-CAFF-42E0-9B3B-9A8E76FF7D9D}.Release|x86.ActiveCfg = Release|Win32 29 | {50C8DCEE-CAFF-42E0-9B3B-9A8E76FF7D9D}.Release|x86.Build.0 = Release|Win32 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {F32C1D7F-2436-4472-BDED-33D559FF7B26} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /JniAtomiThreadPool_VS/JniAtomiThreadPool_VS.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | FullPackMT 10 | Win32 11 | 12 | 13 | FullPackMT 14 | x64 15 | 16 | 17 | Release 18 | Win32 19 | 20 | 21 | Debug 22 | x64 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | 15.0 31 | {50C8DCEE-CAFF-42E0-9B3B-9A8E76FF7D9D} 32 | JniAtomiThreadPoolVS 33 | 8.1 34 | 35 | 36 | 37 | DynamicLibrary 38 | true 39 | v140 40 | MultiByte 41 | 42 | 43 | DynamicLibrary 44 | false 45 | v140 46 | true 47 | MultiByte 48 | 49 | 50 | DynamicLibrary 51 | false 52 | v140 53 | true 54 | MultiByte 55 | 56 | 57 | DynamicLibrary 58 | true 59 | v140 60 | MultiByte 61 | 62 | 63 | DynamicLibrary 64 | false 65 | v140 66 | true 67 | MultiByte 68 | 69 | 70 | DynamicLibrary 71 | false 72 | v140 73 | true 74 | MultiByte 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | Level3 104 | Disabled 105 | true 106 | C:\msys64\home\woonsh\git-project\atomic_threadpool;C:\msys64\home\woonsh\git-project\atomic_threadpool\lfqueue;C:\msys64\home\woonsh\git-project\atomic_threadpool\jni-cross-platform;C:\Program Files\Java\jdk1.7.0_10\include;C:\Program Files\Java\jdk1.7.0_10\include\win32;%(AdditionalIncludeDirectories) 107 | MultiThreaded 108 | 109 | 110 | 111 | 112 | Level3 113 | Disabled 114 | true 115 | C:\msys64\home\woonsh\git-project\atomic_threadpool;C:\msys64\home\woonsh\git-project\atomic_threadpool\lfqueue;C:\msys64\home\woonsh\git-project\atomic_threadpool\jni-cross-platform;C:\Program Files\Java\jdk1.7.0_10\include;C:\Program Files\Java\jdk1.7.0_10\include\win32;%(AdditionalIncludeDirectories) 116 | MultiThreaded 117 | 118 | 119 | 120 | 121 | Level3 122 | MaxSpeed 123 | true 124 | true 125 | true 126 | C:\msys64\home\woonsh\git-project\atomic_threadpool;C:\msys64\home\woonsh\git-project\atomic_threadpool\lfqueue;C:\msys64\home\woonsh\git-project\atomic_threadpool\jni-cross-platform;C:\Program Files\Java\jdk1.7.0_10\include;C:\Program Files\Java\jdk1.7.0_10\include\win32;%(AdditionalIncludeDirectories) 127 | MultiThreadedDLL 128 | 129 | 130 | true 131 | true 132 | 133 | 134 | 135 | 136 | Level3 137 | MaxSpeed 138 | true 139 | true 140 | true 141 | C:\msys64\home\woonsh\git-project\atomic_threadpool;C:\msys64\home\woonsh\git-project\atomic_threadpool\lfqueue;C:\msys64\home\woonsh\git-project\atomic_threadpool\jni-cross-platform;C:\Program Files\Java\jdk1.7.0_10\include;C:\Program Files\Java\jdk1.7.0_10\include\win32;%(AdditionalIncludeDirectories) 142 | MultiThreaded 143 | 144 | 145 | true 146 | true 147 | 148 | 149 | 150 | 151 | Level3 152 | MaxSpeed 153 | true 154 | true 155 | true 156 | C:\msys64\home\woonsh\git-project\atomic_threadpool;C:\msys64\home\woonsh\git-project\atomic_threadpool\lfqueue;C:\msys64\home\woonsh\git-project\atomic_threadpool\jni-cross-platform;C:\Program Files\Java\jdk1.7.0_10\include;C:\Program Files\Java\jdk1.7.0_10\include\win32;%(AdditionalIncludeDirectories) 157 | MultiThreadedDLL 158 | 159 | 160 | true 161 | true 162 | 163 | 164 | 165 | 166 | Level3 167 | MaxSpeed 168 | true 169 | true 170 | true 171 | C:\msys64\home\woonsh\git-project\atomic_threadpool;C:\msys64\home\woonsh\git-project\atomic_threadpool\lfqueue;C:\msys64\home\woonsh\git-project\atomic_threadpool\jni-cross-platform;C:\Program Files\Java\jdk1.7.0_10\include;C:\Program Files\Java\jdk1.7.0_10\include\win32;%(AdditionalIncludeDirectories) 172 | MultiThreaded 173 | 174 | 175 | true 176 | true 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /JniAtomiThreadPool_VS/JniAtomiThreadPool_VS.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | 29 | 30 | Header Files 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2018, Taymindis Woon 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # atomic_threadpool 2 | it is c/c++ library, it's a smallest library that provides a lock-free thread pool sharing on multithreading, it design for scalability 3 | 4 | 5 | ## For Linux OS build 6 | 7 | ## Installation 8 | 9 | ```bash 10 | mkdir build 11 | 12 | cd build 13 | 14 | cmake .. 15 | 16 | make 17 | 18 | sudo make install 19 | 20 | ``` 21 | 22 | 23 | 24 | ## Uninstallation 25 | 26 | ```bash 27 | cd build 28 | 29 | sudo make uninstall 30 | 31 | ``` 32 | 33 | 34 | ## Example to run 35 | ```c 36 | 37 | #include 38 | #include 39 | #include "at_thpool.h" 40 | 41 | 42 | #define TASK_SIZE 200 43 | 44 | void t1(void *arg); 45 | void t2(void *arg); 46 | void t3(void *arg); 47 | void t4(void *arg); 48 | 49 | void t1(void *arg) { 50 | printf("t1 is running on thread #%u \n", (int)pthread_self()); 51 | } 52 | 53 | void t2(void *arg) { 54 | printf("t2 is running on thread #%u\n", (int)pthread_self()); 55 | } 56 | 57 | void t3(void *arg) { 58 | printf("t3 is running on thread #%u\n", (int)pthread_self()); 59 | } 60 | 61 | void t4(void *arg) { 62 | printf("t4 is running on thread #%u\n", (int)pthread_self()); 63 | } 64 | 65 | int main(void) { 66 | int nthreads = 8;//sysconf(_SC_NPROCESSORS_ONLN); // Linux 67 | 68 | printf("Share thread pool with %d threads with at lease totalthroughput * nthreads task size\n", nthreads); 69 | at_thpool_t *thpool = at_thpool_create(nthreads); 70 | 71 | printf("assigned %d tasks between %d threads\n", TASK_SIZE, nthreads); 72 | int i; 73 | for (i = 0; i < TASK_SIZE; i++) { 74 | at_thpool_newtask(thpool, t1, NULL); 75 | at_thpool_newtask(thpool, t2, NULL); 76 | at_thpool_newtask(thpool, t3, NULL); 77 | at_thpool_newtask(thpool, t4, NULL); 78 | } 79 | 80 | #if defined _WIN32 || _WIN64 81 | Sleep(1000); 82 | #else 83 | usleep(1000 * 1000); 84 | #endif 85 | 86 | puts("shutdown thread pool"); 87 | at_thpool_gracefully_shutdown(thpool); 88 | 89 | return 0; 90 | } 91 | 92 | ``` 93 | 94 | 95 | ### How to wait for task to finish on main thread 96 | 97 | AtomicThreadPool design for lock free, it does not wait for anyone, to wait for specified task to finished, client should pass the value to indicate it has done. 98 | 99 | For Example for wait task: 100 | 101 | ```c 102 | 103 | #include 104 | #include 105 | #include "at_thpool.h" 106 | 107 | typedef struct myagent_s { 108 | int has_task_done; 109 | void *my_value; 110 | } my_agent; 111 | 112 | void t1(void *arg); 113 | 114 | void t1(void *arg) { 115 | my_agent *agent = (my_agent*) arg; 116 | 117 | printf("t1 is running on thread #%u \n", (int)pthread_self()); 118 | 119 | /** Doing heavy task **/ 120 | 121 | agent->has_task_done = 1; 122 | 123 | } 124 | 125 | int main(void) { 126 | int nthreads = 8;//sysconf(_SC_NPROCESSORS_ONLN); // Linux 127 | 128 | printf("Share thread pool with %d threads with at lease totalthroughput * nthreads task size\n", nthreads); 129 | at_thpool_t *thpool = at_thpool_create(nthreads); 130 | 131 | int i; 132 | my_agent agent; 133 | agent.has_task_done = 0 134 | 135 | at_thpool_newtask(thpool, t1, &agent); 136 | while (!agent.has_task_done) { 137 | #if defined _WIN32 || _WIN64 138 | Sleep(1); 139 | #else 140 | usleep(1000); 141 | #endif 142 | } 143 | 144 | puts("shutdown thread pool"); 145 | at_thpool_gracefully_shutdown(thpool); 146 | 147 | return 0; 148 | } 149 | 150 | 151 | ``` 152 | 153 | 154 | ## For manual build 155 | gcc -std=c11 -I./ -Ilfqueue/ at_thpool.c lfqueue/lfqueue.c threadpool_example.c -pthread 156 | 157 | 158 | ## for Windows os build 159 | 160 | ### Recommend to use VS2017 to build 161 | 162 | #### include the sources file at_thpool.c at_thpool.h lfqueue.c lfqueue.h into VS2017 project solution. 163 | 164 | Alternatively, 165 | 166 | #### Download the Dev-C++ IDE - https://sourceforge.net/projects/orwelldevcpp/ 167 | 168 | 169 | 170 | #### You can use any IDE/build tools as you wish, just include the source files to your project 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /at_thpool.c: -------------------------------------------------------------------------------- 1 | /* 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2018, Taymindis Woon 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | #include 29 | #include 30 | #include 31 | 32 | #if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__ 33 | #include 34 | #include 35 | #elif defined _WIN32 || _WIN64 36 | #include 37 | #include 38 | #endif 39 | 40 | #include "lfqueue.h" 41 | #include "at_thpool.h" 42 | 43 | /** 44 | * Over max thread will affect the system scalability, it might not scale well 45 | */ 46 | #define MAX_THREADS 64 47 | #define MAX_LFQUEUE 65536 48 | 49 | #define AT_THPOOL_ERROR perror 50 | #define DEF_SPIN_LOCK_CYCLE 2048 51 | #define AT_THPOOL_MALLOC malloc 52 | #define AT_THPOOL_FREE free 53 | 54 | #if defined _WIN32 55 | #define AT_THPOOL_INC(v) InterlockedExchangeAddNoFence(v, 1) 56 | #define AT_THPOOL_DEC(v) InterlockedExchangeAddNoFence(v, -1) 57 | #define AT_THPOOL_SHEDYIELD SwitchToThread 58 | #elif defined _WIN64 59 | #define AT_THPOOL_INC(v) InterlockedExchangeAddNoFence64(v, 1) 60 | #define AT_THPOOL_DEC(v) InterlockedExchangeAddNoFence64(v, -1) 61 | #define AT_THPOOL_SHEDYIELD SwitchToThread 62 | #else 63 | #define AT_THPOOL_INC(v) __sync_fetch_and_add(v, 1) 64 | #define AT_THPOOL_DEC(v) __sync_fetch_and_add(v, -1) 65 | #define AT_THPOOL_SHEDYIELD sched_yield 66 | #endif 67 | 68 | typedef struct { 69 | void (*do_work)(void *); 70 | void *args; 71 | } at_thtask_t; 72 | 73 | struct at_thpool_s { 74 | #if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__ 75 | pthread_t *threads; 76 | #elif defined _WIN32 || _WIN64 77 | HANDLE *threads; 78 | #endif 79 | lfqueue_t taskqueue; 80 | size_t nrunning; 81 | int is_running; 82 | }; 83 | 84 | #if defined _WIN32 || defined _WIN64 85 | unsigned __stdcall at_thpool_worker(void *); 86 | #else 87 | void* at_thpool_worker(void *); 88 | #endif 89 | 90 | at_thpool_t * 91 | at_thpool_create(size_t nthreads) { 92 | size_t i; 93 | if (nthreads > MAX_THREADS) { 94 | fprintf(stderr, "The nthreads is > %d, over max thread will affect the system scalability, it might not scale well\n", MAX_THREADS); 95 | } 96 | 97 | at_thpool_t *tp; 98 | tp = (at_thpool_t*) AT_THPOOL_MALLOC(sizeof(at_thpool_t)); 99 | if (tp == NULL) { 100 | AT_THPOOL_ERROR("malloc"); 101 | return NULL; 102 | } 103 | 104 | #if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__ 105 | tp->threads = (pthread_t *)AT_THPOOL_MALLOC(sizeof(pthread_t) * nthreads); 106 | #elif defined _WIN32 || _WIN64 107 | tp->threads = (HANDLE)AT_THPOOL_MALLOC(sizeof(HANDLE) * nthreads); 108 | #endif 109 | 110 | tp->nrunning = 0; 111 | if (tp->threads == NULL) { 112 | AT_THPOOL_ERROR("malloc"); 113 | AT_THPOOL_FREE(tp); 114 | return NULL; 115 | } 116 | 117 | if (lfqueue_init(&tp->taskqueue) < 0) { 118 | AT_THPOOL_ERROR("malloc"); 119 | AT_THPOOL_FREE(tp->threads); 120 | AT_THPOOL_FREE(tp); 121 | return NULL; 122 | } 123 | 124 | tp->is_running = 1; 125 | 126 | #if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__ 127 | for (i = 0; i < nthreads; i++) { 128 | if (pthread_create(&(tp->threads[i]), NULL, at_thpool_worker, (void*)tp)) { 129 | if (i != 0) { 130 | fprintf(stderr, "maximum thread has reached %zu \n", i ); 131 | break; 132 | } else { 133 | AT_THPOOL_ERROR("Failed to establish thread pool"); 134 | at_thpool_immediate_shutdown(tp); 135 | } 136 | } 137 | pthread_detach(tp->threads[i]); 138 | } 139 | #elif defined _WIN32 || _WIN64 140 | for (i = 0; i < nthreads; i++) { 141 | unsigned udpthreadid; 142 | tp->threads[i] = (HANDLE)_beginthreadex(NULL, 0, at_thpool_worker, (void *)tp, 0, &udpthreadid); 143 | if (tp->threads[i] == 0) { 144 | if (i != 0) { 145 | fprintf(stderr, "maximum thread has reached %lld \n", i); 146 | } 147 | else { 148 | AT_THPOOL_ERROR("Failed to establish thread pool"); 149 | at_thpool_immediate_shutdown(tp); 150 | } 151 | } 152 | CloseHandle(tp->threads[i]); 153 | } 154 | #endif 155 | return tp; 156 | } 157 | 158 | #if defined _WIN32 || defined _WIN64 159 | unsigned __stdcall at_thpool_worker(void *_tp) { 160 | #else 161 | void* at_thpool_worker(void *_tp) { 162 | #endif 163 | at_thpool_t *tp = (at_thpool_t*)_tp; 164 | AT_THPOOL_INC(&tp->nrunning); 165 | 166 | at_thtask_t *task; 167 | void *_task; 168 | lfqueue_t *tq = &tp->taskqueue; 169 | 170 | TASK_PENDING: 171 | while (tp->is_running) { 172 | if ( (_task = lfqueue_deq(tq)) ) { 173 | goto HANDLE_TASK; 174 | } 175 | lfqueue_sleep(1); 176 | } 177 | 178 | AT_THPOOL_DEC(&tp->nrunning); 179 | #if defined _WIN32 || defined _WIN64 180 | return 0; 181 | #else 182 | return NULL; 183 | #endif 184 | HANDLE_TASK: 185 | task = (at_thtask_t*) _task; 186 | task->do_work(task->args); 187 | AT_THPOOL_FREE(task); 188 | goto TASK_PENDING; 189 | } 190 | 191 | int 192 | at_thpool_newtask(at_thpool_t *tp, void (*task_pt)(void *), void *arg) { 193 | at_thtask_t *task = AT_THPOOL_MALLOC(sizeof(at_thtask_t)); 194 | 195 | if (task == NULL) { 196 | AT_THPOOL_ERROR("malloc"); 197 | return errno; 198 | } 199 | 200 | task->do_work = task_pt; 201 | task->args = arg; 202 | 203 | if (lfqueue_enq(&tp->taskqueue, task) == -1) { 204 | fprintf(stderr, "Task unable to assigned to pool, it might be full\n"); 205 | AT_THPOOL_FREE(task); 206 | return -1; 207 | } 208 | return 0; 209 | } 210 | 211 | void 212 | at_thpool_gracefully_shutdown(at_thpool_t *tp) { 213 | tp->is_running = 0; 214 | int i, ncycle = DEF_SPIN_LOCK_CYCLE; 215 | for (;;) { 216 | for (i = 0; i < ncycle; i++) { 217 | if (tp->nrunning == 0) { 218 | goto SHUTDOWN; 219 | } 220 | } 221 | AT_THPOOL_SHEDYIELD(); 222 | } 223 | SHUTDOWN: 224 | lfqueue_destroy(&tp->taskqueue); 225 | lfqueue_sleep(100); 226 | AT_THPOOL_FREE(tp->threads); 227 | AT_THPOOL_FREE(tp); 228 | 229 | } 230 | 231 | void 232 | at_thpool_immediate_shutdown(at_thpool_t *tp) { 233 | tp->is_running = 0; 234 | AT_THPOOL_FREE(tp->threads); 235 | lfqueue_destroy(&tp->taskqueue); 236 | AT_THPOOL_FREE(tp); 237 | } 238 | -------------------------------------------------------------------------------- /at_thpool.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BSD 2-Clause License 3 | * 4 | * Copyright (c) 2018, Taymindis Woon 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * * Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #ifndef _AT_THREADPOOL_H_ 30 | #define _AT_THREADPOOL_H_ 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | 37 | typedef struct at_thpool_s at_thpool_t; 38 | 39 | at_thpool_t *at_thpool_create(size_t nthreads); 40 | 41 | int at_thpool_newtask(at_thpool_t *pool, void (*task_pt)(void *),void *arg); 42 | 43 | void at_thpool_gracefully_shutdown(at_thpool_t *tp); 44 | void at_thpool_immediate_shutdown(at_thpool_t *tp); 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #endif /* _AT_THREADPOOL_H_ */ 51 | -------------------------------------------------------------------------------- /cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 2 | message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 3 | endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 4 | 5 | file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 6 | string(REGEX REPLACE "\n" ";" files "${files}") 7 | foreach(file ${files}) 8 | message(STATUS "Uninstalling $ENV{DESTDIR}${file}") 9 | if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 10 | exec_program( 11 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 12 | OUTPUT_VARIABLE rm_out 13 | RETURN_VALUE rm_retval 14 | ) 15 | if(NOT "${rm_retval}" STREQUAL 0) 16 | message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") 17 | endif(NOT "${rm_retval}" STREQUAL 0) 18 | else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 19 | message(STATUS "File $ENV{DESTDIR}${file} does not exist.") 20 | endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 21 | endforeach(file) -------------------------------------------------------------------------------- /java_source/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.github.taymindis 8 | AtomicThreadPool 9 | ${current.version} 10 | jar 11 | AtomicThreadPool 12 | This is a library which depends on Native C Library https://github.com/Taymindis/atomic_threadpool 13 | 14 | 15 | 1.0-SNAPSHOT 16 | 17 | 18 | 19 | BSD 2-Clause License 20 | https://opensource.org/licenses/BSD-2-Clause 21 | repo 22 | 23 | 24 | https://github.com/Taymindis/atomic_threadpool 25 | 26 | https://github.com/Taymindis/atomic_threadpool.git 27 | scm:git:git://github.com/Taymindis/atomic_threadpool.git 28 | scm:git:git://github.com/Taymindis/atomic_threadpool.git 29 | 30 | 31 | GitHub 32 | https://github.com/Taymindis/atomic_threadpool/issues 33 | 34 | 35 | 36 | 37 | taymindis 38 | Taymindis Woon 39 | minikawoon2017@gmail.com 40 | 41 | 42 | 43 | 44 | 45 | ossrh 46 | https://oss.sonatype.org/content/repositories/snapshots 47 | 48 | 49 | ossrh 50 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 51 | 52 | 53 | 54 | 55 | 56 | junit 57 | junit 58 | 4.12 59 | test 60 | 61 | 62 | 63 | 64 | 65 | 66 | org.apache.maven.plugins 67 | maven-source-plugin 68 | 2.2.1 69 | 70 | 71 | attach-sources 72 | 73 | jar-no-fork 74 | 75 | 76 | 77 | 78 | 79 | org.apache.maven.plugins 80 | maven-javadoc-plugin 81 | 2.9.1 82 | 83 | 84 | attach-javadocs 85 | 86 | jar 87 | 88 | 89 | 90 | 91 | 92 | org.apache.maven.plugins 93 | maven-gpg-plugin 94 | 1.5 95 | 96 | 97 | sign-artifacts 98 | verify 99 | 100 | sign 101 | 102 | 103 | 104 | 105 | 106 | org.apache.maven.plugins 107 | maven-compiler-plugin 108 | 3.1 109 | 110 | 1.7 111 | 1.7 112 | 113 | 114 | 115 | 116 | org.apache.maven.plugins 117 | maven-gpg-plugin 118 | 1.5 119 | 120 | 121 | org.apache.maven.plugins 122 | maven-release-plugin 123 | 2.4.2 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /java_source/src/main/java/com/github/taymindis/AtomicThreadPool.java: -------------------------------------------------------------------------------- 1 | package com.github.taymindis; 2 | 3 | import java.io.IOException; 4 | import java.util.logging.Logger; 5 | 6 | /** 7 | * Created by woonsh on 10/9/2018. 8 | */ 9 | public class AtomicThreadPool { 10 | private long threadpoolPtr = -1; 11 | private static String OS = System.getProperty("os.name").toLowerCase(); 12 | private static final Logger logger = Logger.getLogger(AtomicThreadPool.class.getName()); 13 | 14 | public AtomicThreadPool(int nthreads) { 15 | try { 16 | if (!init(nthreads)) { 17 | throw new Exception("Unable to initialize thread pool correctly"); 18 | } 19 | }catch (Exception e) { 20 | e.printStackTrace(); 21 | } 22 | } 23 | 24 | public native boolean newTask(AtomicThreadPoolTask o); 25 | public native boolean shutdown(); 26 | 27 | public long getThreadpoolPtr() { 28 | return threadpoolPtr; 29 | } 30 | 31 | public void setThreadpoolPtr(long threadpoolPtr) { 32 | this.threadpoolPtr = threadpoolPtr; 33 | } 34 | 35 | private native boolean init(int nthreads); 36 | 37 | private static boolean isWindows32() { 38 | 39 | return ( OS.indexOf("win") >= 0 && "32".equals(System.getProperty("sun.arch.data.model")) ); 40 | 41 | } 42 | 43 | private static boolean isWindows64() { 44 | 45 | return (OS.indexOf("win") >= 0 && "64".equals(System.getProperty("sun.arch.data.model"))); 46 | 47 | } 48 | 49 | private static boolean isMac() { 50 | 51 | return (OS.indexOf("mac") >= 0); 52 | 53 | } 54 | 55 | private static boolean isUnix() { 56 | 57 | return (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0 || OS.indexOf("aix") > 0 ); 58 | 59 | } 60 | 61 | private static boolean isSolaris() { 62 | 63 | return (OS.indexOf("sunos") >= 0); 64 | 65 | } 66 | 67 | static { 68 | try { 69 | if (isWindows32()) { 70 | NativeUtils.loadLibraryFromJar("/VS32.dll"); 71 | } else if (isWindows64()) { 72 | // System.load("C:\\msys64\\home\\woonsh\\git-project\\AtomicThreadPool\\x64\\Release\\AtomicThreadPool.dll"); 73 | NativeUtils.loadLibraryFromJar("/VS64.dll"); 74 | } else if(isMac()){ 75 | // Pending build from source 76 | logger.warning(" Mac is not support yet...."); 77 | // NativeUtils.loadLibraryFromJar("/libatpool_jni.dylib"); 78 | } else { 79 | NativeUtils.loadLibraryFromJar("/libatpool_jni.so"); 80 | } 81 | } catch (IOException e) { 82 | e.printStackTrace(); // This is probably not the best way to handle exception :-) 83 | } catch (UnsatisfiedLinkError e) { 84 | /** It could be no dependencies found, load full pack **/ 85 | logger.warning(" no dependencies found, load full pack library...."); 86 | try { 87 | if (isWindows32()) { 88 | NativeUtils.loadLibraryFromJar("/VS32_full.dll"); 89 | } else if (isWindows64()) { 90 | NativeUtils.loadLibraryFromJar("/VS64_full.dll"); 91 | } else if(isMac()){ 92 | logger.warning(" Mac is not support yet...."); 93 | // NativeUtils.loadLibraryFromJar("/libatpool_jni.dylib"); 94 | } else { 95 | NativeUtils.loadLibraryFromJar("/libatpool_jni.so"); 96 | } 97 | } catch (IOException xe) { 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /java_source/src/main/java/com/github/taymindis/AtomicThreadPoolTask.java: -------------------------------------------------------------------------------- 1 | package com.github.taymindis; 2 | 3 | /** 4 | * Created by woonsh on 10/9/2018. 5 | */ 6 | public interface AtomicThreadPoolTask { 7 | 8 | void runTask(); 9 | } 10 | -------------------------------------------------------------------------------- /java_source/src/main/java/com/github/taymindis/NativeUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Class NativeUtils is published under the The MIT License: 3 | * 4 | * Copyright (c) 2012 Adam Heinrich 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package com.github.taymindis; 25 | 26 | import java.io.File; 27 | import java.io.FileNotFoundException; 28 | import java.io.IOException; 29 | import java.io.InputStream; 30 | import java.nio.file.*; 31 | 32 | /** 33 | * A simple library class which helps with loading dynamic libraries stored in the 34 | * JAR archive. These libraries usually contain implementation of some methods in 35 | * native code (using JNI - Java Native Interface). 36 | * 37 | * @see http://adamheinrich.com/blog/2012/how-to-load-native-jni-library-from-jar 38 | * @see https://github.com/adamheinrich/native-utils 39 | * 40 | */ 41 | public class NativeUtils { 42 | 43 | /** 44 | * The minimum length a prefix for a file has to have according to {@link File#createTempFile(String, String)}}. 45 | */ 46 | private static final int MIN_PREFIX_LENGTH = 3; 47 | public static final String NATIVE_FOLDER_PATH_PREFIX = "nativeutils"; 48 | 49 | /** 50 | * Temporary directory which will contain the DLLs. 51 | */ 52 | private static File temporaryDir; 53 | 54 | /** 55 | * Private constructor - this class will never be instanced 56 | */ 57 | private NativeUtils() { 58 | } 59 | 60 | /** 61 | * Loads library from current JAR archive 62 | * 63 | * The file from JAR is copied into system temporary directory and then loaded. The temporary file is deleted after 64 | * exiting. 65 | * Method uses String as filename because the pathname is "abstract", not system-dependent. 66 | * 67 | * @param path The path of file inside JAR as absolute path (beginning with '/'), e.g. /package/File.ext 68 | * @throws IOException If temporary file creation or read/write operation fails 69 | * @throws IllegalArgumentException If source file (param path) does not exist 70 | * @throws IllegalArgumentException If the path is not absolute or if the filename is shorter than three characters 71 | * (restriction of {@link File#createTempFile(String, String)}). 72 | * @throws FileNotFoundException If the file could not be found inside the JAR. 73 | */ 74 | public static void loadLibraryFromJar(String path) throws IOException, UnsatisfiedLinkError { 75 | 76 | if (null == path || !path.startsWith("/")) { 77 | throw new IllegalArgumentException("The path has to be absolute (start with '/')."); 78 | } 79 | 80 | // Obtain filename from path 81 | String[] parts = path.split("/"); 82 | String filename = (parts.length > 1) ? parts[parts.length - 1] : null; 83 | 84 | // Check if the filename is okay 85 | if (filename == null || filename.length() < MIN_PREFIX_LENGTH) { 86 | throw new IllegalArgumentException("The filename has to be at least 3 characters long."); 87 | } 88 | 89 | // Prepare temporary file 90 | if (temporaryDir == null) { 91 | temporaryDir = createTempDirectory(NATIVE_FOLDER_PATH_PREFIX); 92 | temporaryDir.deleteOnExit(); 93 | } 94 | 95 | File temp = new File(temporaryDir, filename); 96 | InputStream is; 97 | try { 98 | is = NativeUtils.class.getResourceAsStream(path); 99 | Files.copy(is, temp.toPath(), StandardCopyOption.REPLACE_EXISTING); 100 | } catch (IOException e) { 101 | temp.delete(); 102 | throw e; 103 | } catch (NullPointerException e) { 104 | temp.delete(); 105 | throw new FileNotFoundException("File " + path + " was not found inside JAR."); 106 | } 107 | 108 | temp.setReadable(true, false); 109 | 110 | try { 111 | System.load(temp.getAbsolutePath()); 112 | } finally { 113 | if (isPosixCompliant()) { 114 | // Assume POSIX compliant file system, can be deleted after loading 115 | temp.delete(); 116 | } else { 117 | // Assume non-POSIX, and don't delete until last file descriptor closed 118 | temp.deleteOnExit(); 119 | } 120 | } 121 | } 122 | 123 | private static boolean isPosixCompliant() { 124 | try { 125 | return FileSystems.getDefault() 126 | .supportedFileAttributeViews() 127 | .contains("posix"); 128 | } catch (FileSystemNotFoundException e) { 129 | return false; 130 | } catch (ProviderNotFoundException e) { 131 | return false; 132 | } catch (SecurityException e) { 133 | return false; 134 | } 135 | } 136 | 137 | private static File createTempDirectory(String prefix) throws IOException { 138 | String tempDir = System.getProperty("java.io.tmpdir"); 139 | File generatedDir = new File(tempDir, prefix + System.nanoTime()); 140 | 141 | if (!generatedDir.mkdir()) 142 | throw new IOException("Failed to create temp directory " + generatedDir.getName()); 143 | generatedDir.setReadable(true, false); 144 | return generatedDir; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /java_source/src/main/resources/VS32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Taymindis/atomic_threadpool/d77f3b1d1d2e6277645d24dd6fb78cb4d1afa039/java_source/src/main/resources/VS32.dll -------------------------------------------------------------------------------- /java_source/src/main/resources/VS32_full.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Taymindis/atomic_threadpool/d77f3b1d1d2e6277645d24dd6fb78cb4d1afa039/java_source/src/main/resources/VS32_full.dll -------------------------------------------------------------------------------- /java_source/src/main/resources/VS64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Taymindis/atomic_threadpool/d77f3b1d1d2e6277645d24dd6fb78cb4d1afa039/java_source/src/main/resources/VS64.dll -------------------------------------------------------------------------------- /java_source/src/main/resources/VS64_full.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Taymindis/atomic_threadpool/d77f3b1d1d2e6277645d24dd6fb78cb4d1afa039/java_source/src/main/resources/VS64_full.dll -------------------------------------------------------------------------------- /java_source/src/main/resources/libatpool_jni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Taymindis/atomic_threadpool/d77f3b1d1d2e6277645d24dd6fb78cb4d1afa039/java_source/src/main/resources/libatpool_jni.so -------------------------------------------------------------------------------- /java_source/src/test/java/com/github/taymindis/test/MyTask.java: -------------------------------------------------------------------------------- 1 | package com.github.taymindis.test; 2 | 3 | import com.github.taymindis.AtomicThreadPoolTask; 4 | 5 | import java.util.concurrent.atomic.AtomicInteger; 6 | 7 | /** 8 | * Created by woonsh on 10/9/2018. 9 | */ 10 | public class MyTask implements AtomicThreadPoolTask { 11 | 12 | int a = -1; 13 | static AtomicInteger totalRun = null; 14 | 15 | public MyTask(int a) { 16 | if(totalRun == null) { 17 | totalRun = new AtomicInteger(0); 18 | } 19 | this.a = a; 20 | } 21 | 22 | public int getA() { 23 | return a; 24 | } 25 | 26 | public void setA(int a) { 27 | this.a = a; 28 | } 29 | 30 | public void runTask() { 31 | totalRun.getAndIncrement(); 32 | System.out.println("Task is running at " + a + " with thread id " + Thread.currentThread().getId()); 33 | } 34 | 35 | public static AtomicInteger getTotalRun() { 36 | return totalRun; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /java_source/src/test/java/com/github/taymindis/test/Test1.java: -------------------------------------------------------------------------------- 1 | package com.github.taymindis.test; 2 | 3 | import java.io.IOException; 4 | 5 | import com.github.taymindis.AtomicThreadPool; 6 | import org.junit.Test; 7 | import static org.junit.Assert.*; 8 | /** 9 | * Created by woonsh on 10/9/2018. 10 | */ 11 | public class Test1 { 12 | 13 | @Test 14 | public void testRun() throws IOException, InterruptedException { 15 | System.out.println("Thread pool is running in 2 sec"); 16 | Thread.sleep(2000); 17 | AtomicThreadPool p = new AtomicThreadPool(8); 18 | 19 | for(int i=0; i< 1000; i++) { 20 | assertTrue(p.newTask(new MyTask(i))); 21 | } 22 | 23 | Thread.sleep(3000); 24 | assertTrue(MyTask.getTotalRun().intValue() == 1000); 25 | 26 | p.shutdown(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /jni-cross-platform/AtomicThreadPool.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | //#include 8 | #include 9 | 10 | #define callStaticByMethod$(returnType, env, clazz, methodName, sig) \ 11 | (*env)->CallStatic##returnType##Method(env,clazz, (*env)->GetStaticMethodID(env, clazz, methodName, sig)) 12 | #define callStaticByMethod$2(returnType, env, clazz, methodName, sig, ... ) \ 13 | (*env)->CallStatic##returnType##Method(env,clazz, (*env)->GetStaticMethodID(env, clazz, methodName, sig), __VA_ARGS__) 14 | 15 | #define callStaticByField$(returnType, env, clazz, fieldName, sig ) \ 16 | (*env)->GetStatic##returnType##Field(env, clazz, (*env)->GetStaticFieldID(env, clazz, fieldName, sig)) 17 | 18 | #define callByMethod$(returnType, env, clazz, obj$, methodName, sig ) \ 19 | (*env)->Call##returnType##Method(env, obj$, (*env)->GetMethodID(env, clazz, methodName, sig)) 20 | #define callByMethod$2(returnType, env, clazz, obj$, methodName, sig, ... ) \ 21 | (*env)->Call##returnType##Method(env, obj$, (*env)->GetMethodID(env, clazz, methodName, sig), __VA_ARGS__) 22 | 23 | #define callByField$(returnType, env, clazz, obj$, fieldName, sig ) \ 24 | (*env)->Get##returnType##Field(env, obj$, (*env)->GetFieldID(env,clazz, fieldName, sig)) 25 | 26 | static JavaVM *jvm = NULL; // Pointer to the JVM (Java Virtual Machine) 27 | //static JNIEnv *_env = NULL; 28 | void update_curr_jvm(JNIEnv *env); 29 | 30 | void runTask_(void* arg) { 31 | JNIEnv * _env; 32 | jint rs, getEnvStat = (*jvm)->GetEnv(jvm, (void **)&_env, JNI_VERSION_1_6); 33 | if (getEnvStat == JNI_EDETACHED) { 34 | // No attached, attached now 35 | rs = (*jvm)->AttachCurrentThread(jvm, (void**)&_env, NULL); 36 | assert(rs == JNI_OK); 37 | } 38 | 39 | jobject refThreadObj = (jobject)arg; 40 | jclass clz = (*_env)->GetObjectClass(_env, refThreadObj); 41 | callByMethod$(Void, _env, clz, refThreadObj, "runTask", "()V"); 42 | 43 | (*_env)->DeleteGlobalRef(_env, refThreadObj); 44 | (*_env)->DeleteLocalRef(_env, clz); 45 | 46 | rs = (*jvm)->DetachCurrentThread(jvm); 47 | assert(rs == JNI_OK); 48 | } 49 | 50 | JNIEXPORT jboolean JNICALL Java_com_github_taymindis_AtomicThreadPool_init(JNIEnv *env, jobject obj, jint nthreads) { 51 | if (jvm == NULL) { 52 | //_env = env; 53 | update_curr_jvm(env); 54 | } 55 | jclass clz = (*env)->GetObjectClass(env, obj); 56 | printf("%s, %d\n", "Intializing threadpool", nthreads); 57 | at_thpool_t *thpool = at_thpool_create(nthreads); 58 | 59 | callByMethod$2(Void, env, clz, obj, "setThreadpoolPtr", "(J)V", (jlong)thpool); 60 | 61 | /**** 62 | * Local references are garbage collected when the native function returns to Java (when Java calls native) 63 | * or when the calling thread is detached from the JVM (in native calls Java). 64 | * You need explicit DeleteLocalRef only when you have a long lived native function 65 | * (e.g., a main loop) or create a large number of transient objects in a loop 66 | * Since you are return JNI true, DeleteLocalRef is not necessary at this point. 67 | ****/ 68 | 69 | (*env)->DeleteLocalRef(env, clz); 70 | 71 | 72 | return JNI_TRUE; 73 | } 74 | 75 | JNIEXPORT jboolean JNICALL Java_com_github_taymindis_AtomicThreadPool_newTask(JNIEnv *env, jobject obj, jobject threadObj) { 76 | jclass clz = (*env)->GetObjectClass(env, obj); 77 | at_thpool_t *thpool = (at_thpool_t *)callByField$(Long, env, clz, obj, "threadpoolPtr", "J"); 78 | jobject refObj = (*env)->NewGlobalRef(env, threadObj); 79 | if (thpool != NULL && thpool > 0) { 80 | if (at_thpool_newtask(thpool, runTask_, refObj) != -1) { 81 | return JNI_TRUE; 82 | } 83 | } 84 | printf("The pool has not initialized yet"); 85 | (*env)->DeleteLocalRef(env, clz); 86 | return JNI_FALSE; 87 | } 88 | 89 | JNIEXPORT void JNICALL Java_com_github_taymindis_AtomicThreadPool_shutdown(JNIEnv *env, jobject obj) { 90 | jclass clz = (*env)->GetObjectClass(env, obj); 91 | at_thpool_t *thpool =(at_thpool_t *) callByMethod$(Long, env, clz, obj, "getThreadpoolPtr", "()J"); 92 | if (thpool != NULL && thpool > 0) { 93 | at_thpool_gracefully_shutdown(thpool); 94 | } 95 | (*env)->DeleteLocalRef(env, clz); 96 | } 97 | 98 | void update_curr_jvm(JNIEnv *env) { 99 | if (!(*env)->GetJavaVM(env, &jvm) < 0) { 100 | return; 101 | } 102 | jint ver = (*env)->GetVersion(env); // (*env)->GetVersion(); 103 | //cout << ((ver >> 16) & 0x0f) << "." << (ver & 0x0f) ; 104 | //jobject a = callStaticByMethod$2(Object, env, cls2, "getTag", "(I)LTestIvd;", 2); //(*env)->CallStaticObjectMethod(cls2, getTagStaicMethodId, 1); 105 | 106 | //cout << "Field tag id is " << callByMethod$(Int, env, cls2, a, "getId", "()I") << "\n"; 107 | printf("Version is %d\n", ver); 108 | } 109 | 110 | 111 | -------------------------------------------------------------------------------- /jni-cross-platform/AtomicThreadPool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef _ATOMIC_THREADPOOL_H 3 | #define _ATOMIC_THREADPOOL_H 4 | 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | JNIEXPORT jboolean JNICALL Java_com_github_taymindis_AtomicThreadPool_init(JNIEnv *env, jobject obj, jint nthreads); 12 | JNIEXPORT jboolean JNICALL Java_com_github_taymindis_AtomicThreadPool_newTask(JNIEnv *env, jobject obj, jobject threadObj); 13 | JNIEXPORT void JNICALL Java_com_github_taymindis_AtomicThreadPool_shutdown(JNIEnv *env, jobject obj); 14 | 15 | #ifdef __cplusplus 16 | } 17 | #endif 18 | 19 | #endif -------------------------------------------------------------------------------- /threadpool_example.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__ 4 | #include 5 | #elif defined _WIN32 || _WIN64 6 | #include 7 | #include 8 | #endif 9 | #include "at_thpool.h" 10 | 11 | 12 | #define TASK_SIZE 200 13 | 14 | void t1(void *arg); 15 | void t2(void *arg); 16 | void t3(void *arg); 17 | void t4(void *arg); 18 | 19 | void t1(void *arg) { 20 | printf("t1 is running on thread \n"); 21 | } 22 | 23 | void t2(void *arg) { 24 | printf("t2 is running on thread \n"); 25 | } 26 | 27 | void t3(void *arg) { 28 | printf("t3 is running on thread \n"); 29 | } 30 | 31 | void t4(void *arg) { 32 | printf("t4 is running on thread \n"); 33 | } 34 | 35 | int main(void) { 36 | int nthreads = 8;//sysconf(_SC_NPROCESSORS_ONLN); // Linux 37 | 38 | printf("Share thread pool with %d threads with at lease totalthroughput * nthreads task size\n", nthreads); 39 | at_thpool_t *thpool = at_thpool_create(nthreads); 40 | 41 | printf("assigned %d tasks between %d threads\n", TASK_SIZE, nthreads); 42 | int i; 43 | for (i = 0; i < TASK_SIZE; i++) { 44 | at_thpool_newtask(thpool, t1, NULL); 45 | at_thpool_newtask(thpool, t2, NULL); 46 | at_thpool_newtask(thpool, t3, NULL); 47 | at_thpool_newtask(thpool, t4, NULL); 48 | } 49 | 50 | #if defined _WIN32 || _WIN64 51 | Sleep(1000); 52 | #else 53 | sleep(1); 54 | #endif 55 | 56 | puts("shutdown thread pool"); 57 | at_thpool_gracefully_shutdown(thpool); 58 | 59 | return 0; 60 | } --------------------------------------------------------------------------------