├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── appveyor.yml ├── cmake_uninstall.cmake.in ├── example.c ├── example_wins.c ├── lfstack.c ├── lfstack.dev ├── lfstack.h ├── lfstack_vs ├── lfstack_vs.sln ├── lfstack_vs.vcxproj └── lfstack_vs.vcxproj.filters └── test.cpp /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | compiler: 4 | - gcc 5 | - clang 6 | 7 | before_script: 8 | - mkdir build 9 | - cd build 10 | - cmake .. 11 | 12 | script: make && make test 13 | 14 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project(lfstack) 3 | 4 | set(PROJNAME lfstack) 5 | 6 | IF (NOT DEFINED CMAKE_INSTALL_INCLUDEDIR) 7 | SET(CMAKE_INSTALL_INCLUDEDIR /usr/local/include) 8 | ENDIF(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR) 9 | 10 | file(GLOB_RECURSE sources lfstack.c lfstack.h) 11 | file(GLOB_RECURSE sources_test test.cpp) 12 | file(GLOB_RECURSE example_test lfstack.c lfstack.h example.c) 13 | 14 | enable_testing() 15 | add_executable(lfstack-example ${example_test}) 16 | target_link_libraries(lfstack-example PUBLIC pthread) 17 | 18 | include_directories(src /usr/local/include) 19 | 20 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wall -Wstrict-prototypes -Wmissing-prototypes") 21 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-declarations -Wshadow -Wpointer-arith -Wcast-qual") 22 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wsign-compare -std=c11 -pedantic") 23 | 24 | 25 | ############################################################################### 26 | ## packaging ################################################################## 27 | ############################################################################### 28 | add_library(${PROJNAME}.static STATIC ${sources}) 29 | target_link_libraries(${PROJNAME}.static) 30 | set_target_properties(${PROJNAME}.static PROPERTIES OUTPUT_NAME ${PROJNAME}) 31 | add_library(${PROJNAME} SHARED ${sources}) 32 | target_link_libraries(${PROJNAME}) 33 | add_test (NAME lfstack_test COMMAND lfstack-example) 34 | 35 | 36 | # link_directories(/usr/local/lib /usr/lib) 37 | 38 | ## For .a library 39 | install(TARGETS ${PROJNAME}.static EXPORT ${PROJNAME} 40 | ARCHIVE DESTINATION lib${LIB_SUFFIX} 41 | LIBRARY DESTINATION lib${LIB_SUFFIX} 42 | # RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 43 | ) 44 | 45 | ## For .so library 46 | install(TARGETS ${PROJNAME} EXPORT ${PROJNAME} 47 | ARCHIVE DESTINATION lib${LIB_SUFFIX} 48 | LIBRARY DESTINATION lib${LIB_SUFFIX} 49 | # RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 50 | ) 51 | install(FILES lfstack.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lfsaq) 52 | 53 | install(CODE "execute_process(COMMAND ldconfig)") 54 | 55 | configure_file( 56 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" 57 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" 58 | IMMEDIATE @ONLY) 59 | 60 | add_custom_target(uninstall 61 | COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) 62 | 63 | set(CPACK_PACKAGE_NAME "lfstack") 64 | set(CPACK_PACKAGE_VERSION "1.0.0") 65 | 66 | # we don't want to split our program up into several things 67 | set(CPACK_MONOLITHIC_INSTALL 1) 68 | 69 | # This must be last 70 | include(CPack) 71 | -------------------------------------------------------------------------------- /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 | # lfstack [![Build Status](https://travis-ci.org/Taymindis/lfstack.svg?branch=master)](https://travis-ci.org/Taymindis/lfstack) 2 | 3 | lock-free LIFO stack by C native built it, easy built cross platform(no extra dependencies needed) , guarantee thread safety memory management ever! 4 | 5 | # All Platform tests 6 | 7 | GCC/CLANG | [![Build Status](https://travis-ci.org/Taymindis/lfstack.svg?branch=master)](https://travis-ci.org/Taymindis/lfstack) 8 | 9 | VS x64/x86 | [![Build status](https://ci.appveyor.com/api/projects/status/cojd0vosutha2yml/branch/master?svg=true)](https://ci.appveyor.com/project/Taymindis/lfstack/branch/master) 10 | 11 | 12 | ## API 13 | ```c 14 | 15 | extern int lfstack_init(lfstack_t *lfstack); 16 | extern int lfstack_push(lfstack_t *lfstack, void *value); 17 | extern void* lfstack_pop(lfstack_t *lfstack); 18 | extern void* lfstack_single_pop(lfstack_t *lfstack); 19 | extern void lfstack_destroy(lfstack_t *lfstack); 20 | extern size_t lfstack_size(lfstack_t *lfstack); 21 | extern void lfstack_sleep(unsigned int milisec); 22 | 23 | ``` 24 | 25 | 26 | ## Example 27 | 28 | ```c 29 | 30 | int* int_data; 31 | lfstack_t mystack; 32 | 33 | if (lfstack_init(&mystack) == -1) 34 | return -1; 35 | 36 | /** Wrap This scope in other threads **/ 37 | int_data = (int*) malloc(sizeof(int)); 38 | assert(int_data != NULL); 39 | *int_data = i++; 40 | /*PUSH*/ 41 | while (lfstack_push(&mystack, int_data) == -1) { 42 | printf("ENQ Full ?\n"); 43 | } 44 | 45 | /** Wrap This scope in other threads **/ 46 | /*POP*/ 47 | while ( (int_data = lfstack_pop(&mystack)) == NULL) { 48 | printf("POP EMPTY ..\n"); 49 | } 50 | 51 | // printf("%d\n", *(int*) int_data ); 52 | free(int_data); 53 | /** End **/ 54 | 55 | lfstack_destroy(&mystack); 56 | 57 | ``` 58 | 59 | 60 | #### If you are using single thread POP. Please use `lfstack_single_pop` to get better performance 61 | 62 | 63 | ## Build and Installation 64 | 65 | For linux OS, you may use cmake build, for other platforms, please kindly include the source code and header file into the project, e.g. VS2017, DEV-C++, Xcode 66 | 67 | ```bash 68 | mkdir build 69 | 70 | cd build 71 | 72 | cmake .. 73 | 74 | make 75 | 76 | ./lfstack-example 77 | 78 | valgrind --tool=memcheck --leak-check=full ./lfstack-example 79 | 80 | sudo make install 81 | 82 | 83 | ``` 84 | 85 | ## continuously Test 86 | 87 | For continuously test until N number, if you having any issue while testing, please kindly raise an issue 88 | 89 | ```bash 90 | 91 | ./keep-testing.sh 92 | 93 | ``` 94 | 95 | 96 | ## Uninstallation 97 | 98 | ```bash 99 | cd build 100 | 101 | sudo make uninstall 102 | 103 | ``` 104 | 105 | 106 | ## You may also like lock free queue FIFO 107 | 108 | [lfqueue](https://github.com/Taymindis/lfqueue) -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | configuration: Release 3 | platform: 4 | - x86 5 | - x64 6 | build: 7 | verbosity: minimal 8 | after_build: 9 | - cmd: IF "%PLATFORM%"=="x64" ( C:\projects\lfstack\lfstack_vs\%PLATFORM%\Release\lfstack_vs.exe ) ELSE ( C:\projects\lfstack\lfstack_vs\Release\lfstack_vs.exe ) -------------------------------------------------------------------------------- /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) -------------------------------------------------------------------------------- /example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "lfstack.h" 10 | 11 | 12 | typedef void (*test_function)(pthread_t*); 13 | 14 | void one_push_and_multi_pop(pthread_t *threads); 15 | void one_pop_and_multi_push(pthread_t *threads); 16 | void multi_push_pop(pthread_t *threads); 17 | void* worker_push_pop(void *); 18 | void* worker_push(void *); 19 | void* worker_pop(void *); 20 | void* worker_pushingle_c(void *); 21 | 22 | /**Testing must**/ 23 | void one_push_and_multi_pop_must(pthread_t *threads); 24 | void one_pop_must_and_multi_push(pthread_t *threads); 25 | void multi_push_pop_must(pthread_t *threads); 26 | void* worker_push_pop_must(void *); 27 | void* worker_push_must(void *); 28 | void* worker_pop_must(void *); 29 | void* worker_single_pop_must(void *); 30 | 31 | void running_test(test_function testfn); 32 | 33 | struct timeval tv1, tv2; 34 | #define total_put 50000 35 | #define total_running_loop 50 36 | int nthreads = 4; 37 | int one_thread = 1; 38 | int nthreads_exited = 0; 39 | lfstack_t *mystack; 40 | 41 | 42 | void* worker_pop_must(void *arg) { 43 | int i = 0; 44 | int *int_data; 45 | int total_loop = total_put * (*(int*)arg); 46 | while (i++ < total_loop) { 47 | /*Pop*/ 48 | int_data = lfstack_pop_must(mystack); 49 | // printf("%d\n", *int_data); 50 | 51 | free(int_data); 52 | } 53 | __sync_add_and_fetch(&nthreads_exited, 1); 54 | return 0; 55 | } 56 | 57 | void* worker_single_pop_must(void *arg) { 58 | int i = 0; 59 | int *int_data; 60 | int total_loop = total_put * (*(int*)arg); 61 | while (i++ < total_loop) { 62 | /*Pop*/ 63 | int_data = lfstack_single_pop_must(mystack); 64 | // printf("%d\n", *int_data); 65 | 66 | free(int_data); 67 | } 68 | __sync_add_and_fetch(&nthreads_exited, 1); 69 | return 0; 70 | } 71 | 72 | void* worker_push_pop_must(void *arg) 73 | { 74 | int i = 0; 75 | int *int_data; 76 | while (i < total_put) { 77 | int_data = (int*)malloc(sizeof(int)); 78 | assert(int_data != NULL); 79 | *int_data = i++; 80 | /*Push*/ 81 | while (lfstack_push(mystack, int_data)) { 82 | printf("ENQ FULL?\n"); 83 | } 84 | 85 | /*Pop*/ 86 | int_data = lfstack_pop_must(mystack); 87 | // printf("%d\n", *int_data); 88 | free(int_data); 89 | } 90 | __sync_add_and_fetch(&nthreads_exited, 1); 91 | return 0; 92 | } 93 | 94 | void* worker_pop(void *arg) { 95 | int i = 0; 96 | int *int_data; 97 | int total_loop = total_put * (*(int*)arg); 98 | while (i++ < total_loop) { 99 | /*Pop*/ 100 | while ((int_data = lfstack_pop(mystack)) == NULL) { 101 | lfstack_sleep(1); 102 | } 103 | // printf("%d\n", *int_data); 104 | 105 | free(int_data); 106 | } 107 | __sync_add_and_fetch(&nthreads_exited, 1); 108 | return 0; 109 | } 110 | 111 | void* worker_pushingle_c(void *arg) { 112 | int i = 0; 113 | int *int_data; 114 | int total_loop = total_put * (*(int*)arg); 115 | while (i++ < total_loop) { 116 | /*Pop*/ 117 | while ((int_data = lfstack_single_pop(mystack)) == NULL) { 118 | lfstack_sleep(1); 119 | } 120 | // printf("%d\n", *int_data); 121 | 122 | free(int_data); 123 | } 124 | __sync_add_and_fetch(&nthreads_exited, 1); 125 | return 0; 126 | } 127 | 128 | /** Worker Keep Sending at the same time, do not try instensively **/ 129 | void* worker_push(void *arg) 130 | { 131 | int i = 0, *int_data; 132 | int total_loop = total_put * (*(int*)arg); 133 | while (i++ < total_loop) { 134 | int_data = (int*)malloc(sizeof(int)); 135 | assert(int_data != NULL); 136 | *int_data = i; 137 | /*Push*/ 138 | 139 | while (lfstack_push(mystack, int_data)) { 140 | // printf("ENQ FULL?\n"); 141 | } 142 | } 143 | // __sync_add_and_fetch(&nthreads_exited, 1); 144 | return 0; 145 | } 146 | 147 | /** Worker Send And Consume at the same time **/ 148 | void* worker_push_pop(void *arg) 149 | { 150 | int i = 0; 151 | int *int_data; 152 | while (i < total_put) { 153 | int_data = (int*)malloc(sizeof(int)); 154 | assert(int_data != NULL); 155 | *int_data = i++; 156 | /*Push*/ 157 | while (lfstack_push(mystack, int_data)) { 158 | printf("ENQ FULL?\n"); 159 | } 160 | 161 | /*Pop*/ 162 | while ((int_data = lfstack_pop(mystack)) == NULL) { 163 | lfstack_sleep(1); 164 | } 165 | // printf("%d\n", *int_data); 166 | free(int_data); 167 | } 168 | __sync_add_and_fetch(&nthreads_exited, 1); 169 | return 0; 170 | } 171 | 172 | #define join_threads \ 173 | for (i = 0; i < nthreads; i++) {\ 174 | pthread_join(threads[i], NULL); \ 175 | } 176 | 177 | #define detach_thread_and_loop \ 178 | for (i = 0; i < nthreads; i++)\ 179 | pthread_detach(threads[i]);\ 180 | while ( nthreads_exited < nthreads ) \ 181 | lfstack_sleep(10);\ 182 | if(lfstack_size(mystack) != 0){\ 183 | lfstack_sleep(10);\ 184 | } 185 | 186 | void multi_push_pop(pthread_t *threads) { 187 | printf("-----------%s---------------\n", "multi_push_pop"); 188 | int i; 189 | for (i = 0; i < nthreads; i++) { 190 | pthread_create(threads + i, NULL, worker_push_pop, NULL); 191 | } 192 | 193 | join_threads; 194 | // detach_thread_and_loop; 195 | } 196 | 197 | void one_pop_and_multi_push(pthread_t *threads) { 198 | printf("-----------%s---------------\n", "one_pop_and_multi_push"); 199 | int i; 200 | for (i = 0; i < nthreads; i++) 201 | pthread_create(threads + i, NULL, worker_push, &one_thread); 202 | 203 | worker_pushingle_c(&nthreads); 204 | 205 | join_threads; 206 | // detach_thread_and_loop; 207 | } 208 | 209 | void one_push_and_multi_pop(pthread_t *threads) { 210 | printf("-----------%s---------------\n", "one_push_and_multi_pop"); 211 | int i; 212 | for (i = 0; i < nthreads; i++) 213 | pthread_create(threads + i, NULL, worker_pop, &one_thread); 214 | 215 | worker_push(&nthreads); 216 | 217 | #pragma GCC diagnostic push 218 | #pragma GCC diagnostic ignored "-Wimplicit-function-declaration" 219 | detach_thread_and_loop; 220 | #pragma GCC diagnostic pop 221 | 222 | } 223 | 224 | 225 | void one_pop_must_and_multi_push(pthread_t *threads) { 226 | printf("-----------%s---------------\n", "one_pop_must_and_multi_push"); 227 | int i; 228 | for (i = 0; i < nthreads; i++) 229 | pthread_create(threads + i, NULL, worker_push, &one_thread); 230 | 231 | worker_single_pop_must(&nthreads); 232 | 233 | join_threads; 234 | // detach_thread_and_loop; 235 | } 236 | 237 | void one_push_and_multi_pop_must(pthread_t *threads) { 238 | printf("-----------%s---------------\n", "one_push_and_multi_pop_must"); 239 | int i; 240 | for (i = 0; i < nthreads; i++) 241 | pthread_create(threads + i, NULL, worker_pop_must, &one_thread); 242 | 243 | worker_push(&nthreads); 244 | 245 | #pragma GCC diagnostic push 246 | #pragma GCC diagnostic ignored "-Wimplicit-function-declaration" 247 | detach_thread_and_loop; 248 | #pragma GCC diagnostic pop 249 | 250 | } 251 | 252 | void multi_push_pop_must(pthread_t *threads) { 253 | printf("-----------%s---------------\n", "multi_push_pop_must"); 254 | int i; 255 | for (i = 0; i < nthreads; i++) { 256 | pthread_create(threads + i, NULL, worker_push_pop_must, NULL); 257 | } 258 | 259 | join_threads; 260 | // detach_thread_and_loop; 261 | } 262 | 263 | void running_test(test_function testfn) { 264 | int n; 265 | for (n = 0; n < total_running_loop; n++) { 266 | printf("Current running at =%d, ", n); 267 | nthreads_exited = 0; 268 | /* Spawn threads. */ 269 | pthread_t threads[nthreads]; 270 | printf("Using %d thread%s.\n", nthreads, nthreads == 1 ? "" : "s"); 271 | printf("Total requests %d \n", total_put); 272 | gettimeofday(&tv1, NULL); 273 | 274 | testfn(threads); 275 | 276 | gettimeofday(&tv2, NULL); 277 | printf ("Total time = %f seconds\n", 278 | (double) (tv2.tv_usec - tv1.tv_usec) / 1000000 + 279 | (double) (tv2.tv_sec - tv1.tv_sec)); 280 | 281 | lfstack_sleep(10); 282 | assert ( 0 == lfstack_size(mystack) && "Error, all stack should be consumed but not"); 283 | } 284 | } 285 | 286 | int main(void) { 287 | mystack = malloc(sizeof (lfstack_t)); 288 | if (lfstack_init(mystack) == -1) 289 | return -1; 290 | 291 | running_test(one_push_and_multi_pop); 292 | running_test(one_push_and_multi_pop_must); 293 | 294 | running_test(one_pop_and_multi_push); 295 | running_test(one_pop_must_and_multi_push); 296 | 297 | running_test(multi_push_pop); 298 | running_test(multi_push_pop_must); 299 | 300 | 301 | lfstack_destroy(mystack); 302 | // sleep(3); 303 | free(mystack); 304 | 305 | printf("Test Pass!\n"); 306 | 307 | return 0; 308 | } 309 | 310 | -------------------------------------------------------------------------------- /example_wins.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "lfstack.h" 7 | #include 8 | #include 9 | 10 | struct timeval tv1, tv2; 11 | lfstack_t mystack; 12 | 13 | #define nthreads 8 14 | #define total_put 50000 15 | 16 | unsigned __stdcall worker(void *); 17 | unsigned __stdcall worker(void *arg) 18 | { 19 | int i = 0; 20 | int *int_data; 21 | while (i < total_put) { 22 | int_data = (int*)malloc(sizeof(int)); 23 | assert(int_data != NULL); 24 | *int_data = i++; 25 | while (lfstack_push(&mystack, int_data)) { 26 | printf("ENQ FULL?\n"); 27 | } 28 | 29 | while ((int_data = lfstack_pop(&mystack)) == NULL) { 30 | // usleep(1000); 31 | printf("POP EMPTY?\n"); 32 | } 33 | free(int_data); 34 | } 35 | return 0; 36 | } 37 | 38 | #define join_threads \ 39 | for (i = 0; i < nthreads; i++){\ 40 | WaitForSingleObject(threads[i], INFINITE);\ 41 | } 42 | /* 43 | #define detach_thread_and_loop \ 44 | for (i = 0; i < nthreads; i++)\ 45 | pthread_detach(threads[i]);\ 46 | while (1) {\ 47 | sleep(2);\ 48 | printf("current size= %zu\n", lfstack_size(&mystack) );\ 49 | }*/ 50 | 51 | 52 | int main(void) 53 | { 54 | //const static int nthreads = 2;//sysconf(_SC_NPROCESSORS_ONLN); // Linux 55 | int i, n; 56 | if (lfstack_init(&mystack) == -1) 57 | return -1; 58 | 59 | for (n = 0; n < 100; n++) { 60 | /* Spawn threads. */ 61 | printf("Current running at %d, Total threads = %d\n", n, nthreads); 62 | clock_t start = clock(); 63 | HANDLE threads[nthreads]; 64 | 65 | for (i = 0; i < nthreads; i++) { 66 | unsigned udpthreadid; 67 | threads[i] = (HANDLE)_beginthreadex(NULL, 0, worker, NULL, 0, &udpthreadid); 68 | } 69 | 70 | join_threads; 71 | // detach_thread_and_loop; 72 | 73 | clock_t end = clock(); 74 | 75 | printf("Total time = %f seconds\n", (float)(end - start) / CLOCKS_PER_SEC); 76 | 77 | assert(0 == lfstack_size(&mystack) && "Error, all queue should be consumed but not"); 78 | 79 | } 80 | printf("Take a 4 seconds sleep \n"); 81 | Sleep(4000); 82 | printf("Flush all the inactive memory \n"); 83 | lfstack_flush(&mystack); 84 | //printf("Press Any Key to Continue\n"); 85 | lfstack_destroy(&mystack); 86 | return 0; 87 | } 88 | 89 | -------------------------------------------------------------------------------- /lfstack.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * BSD 2-Clause License 4 | * 5 | * Copyright (c) 2018, Taymindis Woon 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright notice, this 12 | * list of conditions and the following disclaimer. 13 | * 14 | * * Redistributions in binary form must reproduce the above copyright notice, 15 | * this list of conditions and the following disclaimer in the documentation 16 | * and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | */ 30 | #include 31 | #include 32 | #include 33 | #if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__ 34 | 35 | #include 36 | #include // for usleep 37 | #include 38 | 39 | #define __LFS_VAL_COMPARE_AND_SWAP __sync_val_compare_and_swap 40 | #define __LFS_BOOL_COMPARE_AND_SWAP __sync_bool_compare_and_swap 41 | #define __LFS_FETCH_AND_ADD __sync_fetch_and_add 42 | #define __LFS_ADD_AND_FETCH __sync_add_and_fetch 43 | #define __LFS_YIELD_THREAD sched_yield 44 | #define __LFS_SYNC_MEMORY __sync_synchronize 45 | 46 | #else 47 | 48 | #include 49 | #include 50 | #ifdef _WIN64 51 | inline BOOL __SYNC_BOOL_CAS(LONG64 volatile *dest, LONG64 input, LONG64 comparand) { 52 | return InterlockedCompareExchangeNoFence64(dest, input, comparand) == comparand; 53 | } 54 | #define __LFS_VAL_COMPARE_AND_SWAP(dest, comparand, input) \ 55 | InterlockedCompareExchangeNoFence64((LONG64 volatile *)dest, (LONG64)input, (LONG64)comparand) 56 | #define __LFS_BOOL_COMPARE_AND_SWAP(dest, comparand, input) \ 57 | __SYNC_BOOL_CAS((LONG64 volatile *)dest, (LONG64)input, (LONG64)comparand) 58 | #define __LFS_FETCH_AND_ADD InterlockedExchangeAddNoFence64 59 | #define __LFS_ADD_AND_FETCH InterlockedAddNoFence64 60 | #define __LFS_SYNC_MEMORY MemoryBarrier 61 | 62 | #else 63 | #ifndef asm 64 | #define asm __asm 65 | #endif 66 | inline BOOL __SYNC_BOOL_CAS(LONG volatile *dest, LONG input, LONG comparand) { 67 | return InterlockedCompareExchangeNoFence(dest, input, comparand) == comparand; 68 | } 69 | #define __LFS_VAL_COMPARE_AND_SWAP(dest, comparand, input) \ 70 | InterlockedCompareExchangeNoFence((LONG volatile *)dest, (LONG)input, (LONG)comparand) 71 | #define __LFS_BOOL_COMPARE_AND_SWAP(dest, comparand, input) \ 72 | __SYNC_BOOL_CAS((LONG volatile *)dest, (LONG)input, (LONG)comparand) 73 | #define __LFS_FETCH_AND_ADD InterlockedExchangeAddNoFence 74 | #define __LFS_ADD_AND_FETCH InterlockedAddNoFence 75 | #define __LFS_SYNC_MEMORY() asm mfence 76 | 77 | #endif 78 | #include 79 | #define __LFS_YIELD_THREAD SwitchToThread 80 | #endif 81 | 82 | #include "lfstack.h" 83 | #define DEF_LFS_ASSIGNED_SPIN 2048 84 | 85 | #if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__ 86 | #define lfs_time_t long 87 | #define lfs_get_curr_time(_time_sec) \ 88 | struct timeval _time_; \ 89 | gettimeofday(&_time_, NULL); \ 90 | *_time_sec = _time_.tv_sec 91 | #define lfs_diff_time(_etime_, _stime_) _etime_ - _stime_ 92 | #else 93 | #define lfs_time_t time_t 94 | #define lfs_get_curr_time(_time_sec) time(_time_sec) 95 | #define lfs_diff_time(_etime_, _stime_) difftime(_etime_, _stime_) 96 | #endif 97 | 98 | struct lfstack_cas_node_s { 99 | void * value; 100 | struct lfstack_cas_node_s *prev, *nextfree; 101 | lfs_time_t _deactivate_tm; 102 | }; 103 | 104 | static void __lfs_recycle_free(lfstack_t *, lfstack_cas_node_t*); 105 | static void _lfs_check_free(lfstack_t *); 106 | static void *_pop(lfstack_t *); 107 | static void *_single_pop(lfstack_t *); 108 | static int _push(lfstack_t *, void* ); 109 | static inline void* _lfstack_malloc(void* pl, size_t sz) { 110 | return malloc(sz); 111 | } 112 | static inline void _lfstack_free(void* pl, void* ptr) { 113 | free(ptr); 114 | } 115 | 116 | static void * 117 | _pop(lfstack_t *lfs) { 118 | lfstack_cas_node_t *head, *prev; 119 | void *val; 120 | 121 | for (;;) { 122 | head = lfs->head; 123 | __LFS_SYNC_MEMORY(); 124 | /** ABA PROBLEM? in order to solve this, I use time free to avoid realloc the same aligned address **/ 125 | if (lfs->head == head) { 126 | prev = head->prev; 127 | if (prev) { 128 | if (__LFS_BOOL_COMPARE_AND_SWAP(&lfs->head, head, prev)) { 129 | val = head->value; 130 | break; 131 | } 132 | } else { 133 | /** Empty **/ 134 | val = NULL; 135 | goto _done; 136 | } 137 | } 138 | } 139 | __lfs_recycle_free(lfs, head); 140 | __LFS_YIELD_THREAD(); 141 | _done: 142 | // __asm volatile("" ::: "memory"); 143 | __LFS_SYNC_MEMORY(); 144 | _lfs_check_free(lfs); 145 | return val; 146 | } 147 | 148 | static void * 149 | _single_pop(lfstack_t *lfs) { 150 | lfstack_cas_node_t *head, *prev; 151 | void *val; 152 | 153 | for (;;) { 154 | head = lfs->head; 155 | __LFS_SYNC_MEMORY(); 156 | if (lfs->head == head) { 157 | prev = head->prev; 158 | if (prev) { 159 | if (__LFS_BOOL_COMPARE_AND_SWAP(&lfs->head, head, prev)) { 160 | val = head->value; 161 | lfs->_free(lfs->pl, head); 162 | break; 163 | } 164 | } else { 165 | /** Empty **/ 166 | return NULL; 167 | } 168 | } 169 | } 170 | return val; 171 | } 172 | 173 | static int 174 | _push(lfstack_t *lfs, void* value) { 175 | lfstack_cas_node_t *head, *new_head; 176 | new_head = (lfstack_cas_node_t*) lfs->_malloc(lfs->pl, sizeof(lfstack_cas_node_t)); 177 | if (new_head == NULL) { 178 | perror("malloc"); 179 | return errno; 180 | } 181 | new_head->value = value; 182 | new_head->nextfree = NULL; 183 | for (;;) { 184 | __LFS_SYNC_MEMORY(); 185 | new_head->prev = head = lfs->head; 186 | if (__LFS_BOOL_COMPARE_AND_SWAP(&lfs->head, head, new_head)) { 187 | // always check any free value 188 | _lfs_check_free(lfs); 189 | return 0; 190 | } 191 | } 192 | 193 | /*It never be here*/ 194 | return -1; 195 | } 196 | 197 | static void 198 | __lfs_recycle_free(lfstack_t *lfs, lfstack_cas_node_t* freenode) { 199 | lfstack_cas_node_t *freed; 200 | do { 201 | freed = lfs->move_free; 202 | } while (!__LFS_BOOL_COMPARE_AND_SWAP(&freed->nextfree, NULL, freenode) ); 203 | 204 | lfs_get_curr_time(&freenode->_deactivate_tm); 205 | 206 | __LFS_BOOL_COMPARE_AND_SWAP(&lfs->move_free, freed, freenode); 207 | } 208 | 209 | static void 210 | _lfs_check_free(lfstack_t *lfs) { 211 | lfs_time_t curr_time; 212 | if (__LFS_BOOL_COMPARE_AND_SWAP(&lfs->in_free_mode, 0, 1)) { 213 | lfs_get_curr_time(&curr_time); 214 | lfstack_cas_node_t *rtfree = lfs->root_free, *nextfree; 215 | while ( rtfree && (rtfree != lfs->move_free) ) { 216 | nextfree = rtfree->nextfree; 217 | if ( lfs_diff_time(curr_time, rtfree->_deactivate_tm) > 2) { 218 | // printf("%p\n", rtfree); 219 | lfs->_free(lfs->pl, rtfree); 220 | rtfree = nextfree; 221 | } else { 222 | break; 223 | } 224 | } 225 | lfs->root_free = rtfree; 226 | __LFS_BOOL_COMPARE_AND_SWAP(&lfs->in_free_mode, 1, 0); 227 | } 228 | __LFS_SYNC_MEMORY(); 229 | } 230 | 231 | int 232 | lfstack_init(lfstack_t *lfs) { 233 | return lfstack_init_mf(lfs, NULL, _lfstack_malloc, _lfstack_free); 234 | } 235 | 236 | int 237 | lfstack_init_mf(lfstack_t *lfs, void* pl, lfstack_malloc_fn lfs_malloc, lfstack_free_fn lfs_free) { 238 | lfs->_malloc = lfs_malloc; 239 | lfs->_free = lfs_free; 240 | lfs->pl = pl; 241 | 242 | lfstack_cas_node_t *base = lfs->_malloc(lfs->pl, sizeof(lfstack_cas_node_t)); 243 | lfstack_cas_node_t *freebase = lfs->_malloc(lfs->pl, sizeof(lfstack_cas_node_t)); 244 | if (base == NULL || freebase == NULL) { 245 | perror("malloc"); 246 | return errno; 247 | } 248 | base->value = NULL; 249 | base->prev = NULL; 250 | base->nextfree = NULL; 251 | base->_deactivate_tm = 0; 252 | 253 | freebase->value = NULL; 254 | freebase->prev = NULL; 255 | freebase->nextfree = NULL; 256 | freebase->_deactivate_tm = 0; 257 | 258 | lfs->head = base; // Not yet to be free for first node only 259 | lfs->root_free = lfs->move_free = freebase; // Not yet to be free for first node only 260 | lfs->size = 0; 261 | lfs->in_free_mode = 0; 262 | 263 | return 0; 264 | } 265 | 266 | void 267 | lfstack_destroy(lfstack_t *lfs) { 268 | void* p; 269 | while ((p = lfstack_pop(lfs))) { 270 | lfs->_free(lfs->pl, p); 271 | } 272 | // Clear the recycle chain nodes 273 | lfstack_cas_node_t *rtfree = lfs->root_free, *nextfree; 274 | while (rtfree && (rtfree != lfs->move_free) ) { 275 | nextfree = rtfree->nextfree; 276 | lfs->_free(lfs->pl, rtfree); 277 | rtfree = nextfree; 278 | } 279 | if (rtfree) { 280 | lfs->_free(lfs->pl, rtfree); 281 | } 282 | 283 | lfs->_free(lfs->pl, lfs->head); // Last free 284 | 285 | lfs->size = 0; 286 | } 287 | 288 | void lfstack_flush(lfstack_t *lfstack) { 289 | _lfs_check_free(lfstack); 290 | } 291 | 292 | int 293 | lfstack_push(lfstack_t *lfs, void *value) { 294 | if (_push(lfs, value)) { 295 | return -1; 296 | } 297 | __LFS_ADD_AND_FETCH(&lfs->size, 1); 298 | return 0; 299 | } 300 | 301 | void* 302 | lfstack_pop(lfstack_t *lfs) { 303 | void *v; 304 | if (//__LFS_ADD_AND_FETCH(&lfs->size, 0) && 305 | (v = _pop(lfs)) 306 | ) { 307 | 308 | __LFS_FETCH_AND_ADD(&lfs->size, -1); 309 | return v; 310 | } 311 | // Rest the thread for other thread, to avoid keep looping force 312 | lfstack_sleep(1); 313 | return NULL; 314 | } 315 | 316 | void* 317 | lfstack_pop_must(lfstack_t *lfs) { 318 | void *v; 319 | while ( !(v = _pop(lfs)) ) { 320 | // Rest the thread for other thread, to avoid keep looping force 321 | lfstack_sleep(1); 322 | } 323 | __LFS_FETCH_AND_ADD(&lfs->size, -1); 324 | return v; 325 | } 326 | 327 | /**This is only applicable when only single thread consume only**/ 328 | void* 329 | lfstack_single_pop(lfstack_t *lfs) { 330 | void *v; 331 | if (//__LFS_ADD_AND_FETCH(&lfs->size, 0) && 332 | (v = _single_pop(lfs)) 333 | ) { 334 | 335 | __LFS_FETCH_AND_ADD(&lfs->size, -1); 336 | return v; 337 | } 338 | // Rest the thread for other thread, to avoid keep looping force 339 | lfstack_sleep(1); 340 | return NULL; 341 | } 342 | 343 | void* 344 | lfstack_single_pop_must(lfstack_t *lfs) { 345 | void *v; 346 | while ( !(v = _single_pop(lfs)) ) { 347 | // Rest the thread for other thread, to avoid keep looping force 348 | lfstack_sleep(1); 349 | } 350 | __LFS_FETCH_AND_ADD(&lfs->size, -1); 351 | return v; 352 | } 353 | 354 | size_t 355 | lfstack_size(lfstack_t *lfs) { 356 | return __LFS_ADD_AND_FETCH(&lfs->size, 0); 357 | } 358 | 359 | void 360 | lfstack_sleep(unsigned int milisec) { 361 | #if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__ 362 | #pragma GCC diagnostic push 363 | #pragma GCC diagnostic ignored "-Wimplicit-function-declaration" 364 | usleep(milisec * 1000); 365 | #pragma GCC diagnostic pop 366 | #else 367 | Sleep(milisec); 368 | #endif 369 | } 370 | 371 | #ifdef __cplusplus 372 | } 373 | #endif 374 | -------------------------------------------------------------------------------- /lfstack.dev: -------------------------------------------------------------------------------- 1 | [Project] 2 | FileName=lfstack.dev 3 | Name=lfstack 4 | Type=1 5 | Ver=2 6 | ObjFiles= 7 | Includes= 8 | Libs= 9 | PrivateResource= 10 | ResourceIncludes= 11 | MakeIncludes= 12 | Compiler= 13 | CppCompiler= 14 | Linker= 15 | IsCpp=0 16 | Icon= 17 | ExeOutput= 18 | ObjectOutput= 19 | LogOutput= 20 | LogOutputEnabled=0 21 | OverrideOutput=0 22 | OverrideOutputName= 23 | HostApplication= 24 | UseCustomMakefile=0 25 | CustomMakefile= 26 | CommandLine= 27 | Folders= 28 | IncludeVersionInfo=0 29 | SupportXPThemes=0 30 | CompilerSet=1 31 | CompilerSettings=0000000000000000001000000 32 | UnitCount=3 33 | 34 | [VersionInfo] 35 | Major=1 36 | Minor=0 37 | Release=0 38 | Build=0 39 | LanguageID=1033 40 | CharsetID=1252 41 | CompanyName= 42 | FileVersion= 43 | FileDescription=Developed using the Dev-C++ IDE 44 | InternalName= 45 | LegalCopyright= 46 | LegalTrademarks= 47 | OriginalFilename= 48 | ProductName= 49 | ProductVersion= 50 | AutoIncBuildNr=0 51 | SyncProduct=1 52 | 53 | [Unit1] 54 | FileName=example.c 55 | CompileCpp=0 56 | Folder= 57 | Compile=1 58 | Link=1 59 | Priority=1000 60 | OverrideBuildCmd=0 61 | BuildCmd= 62 | 63 | [Unit2] 64 | FileName=lfstack.c 65 | CompileCpp=0 66 | Folder= 67 | Compile=1 68 | Link=1 69 | Priority=1000 70 | OverrideBuildCmd=0 71 | BuildCmd= 72 | 73 | [Unit3] 74 | FileName=lfstack.h 75 | CompileCpp=0 76 | Folder= 77 | Compile=1 78 | Link=1 79 | Priority=1000 80 | OverrideBuildCmd=0 81 | BuildCmd= 82 | 83 | -------------------------------------------------------------------------------- /lfstack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * BSD 2-Clause License 4 | * 5 | * Copyright (c) 2018, Taymindis Woon 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright notice, this 12 | * list of conditions and the following disclaimer. 13 | * 14 | * * Redistributions in binary form must reproduce the above copyright notice, 15 | * this list of conditions and the following disclaimer in the documentation 16 | * and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | */ 30 | 31 | #ifndef LFSTACK_H 32 | #define LFSTACK_H 33 | 34 | #include 35 | #include 36 | 37 | #ifdef __cplusplus 38 | extern "C" { 39 | #endif 40 | 41 | typedef struct lfstack_cas_node_s lfstack_cas_node_t; 42 | typedef void* (*lfstack_malloc_fn)(void*, size_t); 43 | typedef void (*lfstack_free_fn)(void*, void*); 44 | 45 | #if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__ 46 | #define lfs_bool_t int 47 | #else 48 | #ifdef _WIN64 49 | #define lfs_bool_t int64_t 50 | #else 51 | #define lfs_bool_t int 52 | #endif 53 | #endif 54 | 55 | typedef struct { 56 | lfstack_cas_node_t *head, *root_free, *move_free; 57 | volatile size_t size; 58 | volatile lfs_bool_t in_free_mode; 59 | lfstack_malloc_fn _malloc; 60 | lfstack_free_fn _free; 61 | void *pl; 62 | } lfstack_t; 63 | 64 | extern int lfstack_init(lfstack_t *lfstack); 65 | extern int lfstack_init_mf(lfstack_t *lfs, void* pl, lfstack_malloc_fn lfs_malloc, lfstack_free_fn lfs_free); 66 | extern int lfstack_push(lfstack_t *lfstack, void *value); 67 | extern void* lfstack_pop(lfstack_t *lfstack); 68 | extern void* lfstack_single_pop(lfstack_t *lfstack); 69 | 70 | /** loop until value been pop, it sleeps 1ms if not found, to reduce cpu high usage **/ 71 | extern void* lfstack_pop_must(lfstack_t *lfstack); 72 | extern void* lfstack_single_pop_must(lfstack_t *lfstack); 73 | 74 | /*** lfstack_flush to flush all the inacitve element ***/ 75 | extern void lfstack_flush(lfstack_t *lfstack); 76 | extern void lfstack_destroy(lfstack_t *lfstack); 77 | extern size_t lfstack_size(lfstack_t *lfstack); 78 | extern void lfstack_sleep(unsigned int milisec); 79 | 80 | 81 | #ifdef __cplusplus 82 | } 83 | #endif 84 | 85 | #endif 86 | 87 | -------------------------------------------------------------------------------- /lfstack_vs/lfstack_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}") = "lfstack_vs", "lfstack_vs.vcxproj", "{C08C7611-D4DA-4FBE-8808-3E474223F691}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {C08C7611-D4DA-4FBE-8808-3E474223F691}.Debug|x64.ActiveCfg = Debug|x64 17 | {C08C7611-D4DA-4FBE-8808-3E474223F691}.Debug|x64.Build.0 = Debug|x64 18 | {C08C7611-D4DA-4FBE-8808-3E474223F691}.Debug|x86.ActiveCfg = Debug|Win32 19 | {C08C7611-D4DA-4FBE-8808-3E474223F691}.Debug|x86.Build.0 = Debug|Win32 20 | {C08C7611-D4DA-4FBE-8808-3E474223F691}.Release|x64.ActiveCfg = Release|x64 21 | {C08C7611-D4DA-4FBE-8808-3E474223F691}.Release|x64.Build.0 = Release|x64 22 | {C08C7611-D4DA-4FBE-8808-3E474223F691}.Release|x86.ActiveCfg = Release|Win32 23 | {C08C7611-D4DA-4FBE-8808-3E474223F691}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {A5B792B3-4685-4389-B1E4-C8BA4F94A888} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /lfstack_vs/lfstack_vs.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {C08C7611-D4DA-4FBE-8808-3E474223F691} 24 | lfstackvs 25 | 8.1 26 | 27 | 28 | 29 | Application 30 | true 31 | v140 32 | MultiByte 33 | 34 | 35 | Application 36 | false 37 | v140 38 | true 39 | MultiByte 40 | 41 | 42 | Application 43 | true 44 | v140 45 | MultiByte 46 | 47 | 48 | Application 49 | false 50 | v140 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | Disabled 77 | true 78 | 79 | 80 | 81 | 82 | Level3 83 | Disabled 84 | true 85 | 86 | 87 | 88 | 89 | Level3 90 | MaxSpeed 91 | true 92 | true 93 | true 94 | 95 | 96 | true 97 | true 98 | 99 | 100 | 101 | 102 | Level3 103 | MaxSpeed 104 | true 105 | true 106 | true 107 | 108 | 109 | true 110 | true 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /lfstack_vs/lfstack_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 | 26 | 27 | Header Files 28 | 29 | 30 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "lfstack.h" 10 | 11 | 12 | lfstack_t results; 13 | 14 | void *worker(void *arg) 15 | { 16 | int i = 10000; 17 | long long *int_data; 18 | while (i--) { 19 | int_data = (long long*) malloc(sizeof(long long)); 20 | assert(int_data != NULL); 21 | *int_data = i; 22 | while (lfstack_push(&results, int_data) == -1) ; 23 | 24 | while ( (int_data =(long long*) lfstack_pop(&results)) == NULL); 25 | 26 | free(int_data); 27 | 28 | } 29 | 30 | return NULL; 31 | } 32 | 33 | TEST(lfstackTest, CROSS_THREAD_MAIN_CALL) { 34 | int nthreads = sysconf(_SC_NPROCESSORS_ONLN); // Linux 35 | int i; 36 | 37 | lfstack_init(&results); 38 | 39 | /* Spawn threads. */ 40 | pthread_t threads[nthreads]; 41 | printf("Using %d thread%s.\n", nthreads, nthreads == 1 ? "" : "s"); 42 | for (i = 0; i < nthreads; i++) 43 | pthread_create(threads + i, NULL, worker, NULL); 44 | 45 | 46 | for (i = 0; i < nthreads; i++) 47 | pthread_join(threads[i], NULL); 48 | 49 | lfstack_destroy(&results); 50 | } 51 | 52 | int main(int argc, char **argv) { 53 | ::testing::InitGoogleTest(&argc, argv); 54 | return RUN_ALL_TESTS(); 55 | } 56 | --------------------------------------------------------------------------------