├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── dispatch-c++.cc ├── dispatch-c++.h ├── libdispatch-c++.sublime-project └── test_main.cc /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X Specific 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # Icon must end with two \r 7 | Icon 8 | 9 | # # Thumbnails 10 | ._* 11 | 12 | # Files that might appear on external disk 13 | .Spotlight-V100 14 | .Trashes 15 | 16 | # Directories potentially created on remote AFP share 17 | .AppleDB 18 | .AppleDesktop 19 | Network Trash Folder 20 | Temporary Items 21 | .apdisk 22 | 23 | # Xcode project temporary files 24 | build/ 25 | *.pbxuser 26 | !default.pbxuser 27 | *.mode1v3 28 | !default.mode1v3 29 | *.mode2v3 30 | !default.mode2v3 31 | *.perspectivev3 32 | !default.perspectivev3 33 | xcuserdata 34 | *.xccheckout 35 | *.moved-aside 36 | DerivedData 37 | *.hmap 38 | *.ipa 39 | *.xcuserstate 40 | 41 | # cache files for sublime text 42 | *.tmlanguage.cache 43 | *.tmPreferences.cache 44 | *.stTheme.cache 45 | 46 | # workspace files are user-specific 47 | *.sublime-workspace 48 | 49 | # sftp configuration file 50 | sftp-config.json 51 | 52 | # Compiled Object files 53 | *.slo 54 | *.lo 55 | *.o 56 | *.obj 57 | 58 | # Precompiled Headers 59 | *.gch 60 | *.pch 61 | 62 | # Compiled Dynamic libraries 63 | *.so 64 | *.dylib 65 | *.dll 66 | 67 | # Fortran module files 68 | *.mod 69 | 70 | # Compiled Static libraries 71 | *.lai 72 | *.la 73 | *.a 74 | *.lib 75 | 76 | # Executables 77 | *.exe 78 | *.out 79 | *.app 80 | 81 | # Ignore tags created by etags, ctags, gtags (GNU global) and cscope 82 | TAGS 83 | tags 84 | gtags.files 85 | GTAGS 86 | GRTAGS 87 | GPATH 88 | cscope.files 89 | .tags 90 | .tags_sorted_by_file 91 | .gemtags 92 | 93 | # Project specifics 94 | test_main 95 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Junjie LU 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | INC = -I. 2 | OBJS = dispatch-c++.o 3 | LIB_BIN = libdispatch-c++.a 4 | TEST_BIN = test_main 5 | 6 | MY_CPPFLAGS ?= 7 | MY_CXXFLAGS ?= -Wall -Ofast -funroll-loops -flto 8 | 9 | AR = ar 10 | ARFLAGS = rcu 11 | RANLIB = ranlib 12 | CPPFLAGS = $(INC) -Dtest_main=main $(MY_CPPFLAGS) 13 | CXXFLAGS = -std=c++1y $(MY_CXXFLAGS) 14 | LOADLIBES = -L. 15 | LDLIBS = -ldispatch-c++ 16 | 17 | .PHONY: all clean test 18 | 19 | all: $(LIB_BIN) 20 | 21 | $(LIB_BIN): $(OBJS) 22 | $(AR) $(ARFLAGS) $@ $^ 23 | $(RANLIB) $@ 24 | 25 | test: $(LIB_BIN) $(TEST_BIN) 26 | ./$(TEST_BIN) 27 | 28 | clean: 29 | $(RM) $(LIB_BIN) $(OBJS) $(TEST_BIN) 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libdispatch-c++ 2 | 3 | A C++ wrapper of `libdispatch`. 4 | 5 | Although `libdispatch` can be used as a pure C library, sometimes we want to take advantage of lambdas in C++11. That's my first motivation. 6 | 7 | ## Requirements 8 | 9 | - libdispatch 10 | - OS X (After 10.6 Snow Leopard): Just install Xcode and it's already done. 11 | - Ubuntu: `sudo apt-get install libdispatch-dev` 12 | - A C++ compiler supporting C++11 13 | - `make` 14 | 15 | ## How to use 16 | 17 | Just `make`. What you need are `dispatch-c++.h` and `libdispatch-c++.a`. The way to use them depends on your habits, anyway, let your compile toolchain know them. 18 | 19 | `make test` to test the library can work on your compile toolchain. The expected result of `make test` is just printing "Success!" on terminal. `test_main.cpp` is an example of using `libdispatch-c++` in your program. 20 | 21 | Be careful with the asynchronous functions! 22 | 23 | ## License 24 | 25 | BSD 2-Clause License. 26 | -------------------------------------------------------------------------------- /dispatch-c++.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "dispatch-c++.h" 4 | 5 | /* 6 | * For synchronous dispatch. 7 | */ 8 | static void call_func_void_void(void * context) 9 | { 10 | std::function &func = *static_cast *>(context); 11 | 12 | func(); 13 | } 14 | 15 | /* 16 | * For asynchronous dispatch. 17 | */ 18 | static void call_funcptr_void_void(void * context) 19 | { 20 | std::function * func_ptr = static_cast *>(context); 21 | 22 | (*func_ptr)(); 23 | 24 | delete func_ptr; 25 | } 26 | 27 | /* 28 | * For synchronous dispatch. 29 | */ 30 | static void call_func_void_size_t(void * context, size_t idx) 31 | { 32 | std::function &func = *static_cast *>(context); 33 | 34 | func(idx); 35 | } 36 | 37 | namespace dispatch { 38 | void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, const std::function &func) 39 | { 40 | std::function * func_ptr = new std::function(func); 41 | 42 | dispatch_after_f(when, queue, static_cast(func_ptr), call_funcptr_void_void); 43 | } 44 | 45 | void dispatch_apply(size_t iterations, dispatch_queue_t queue, const std::function &func) 46 | { 47 | dispatch_apply_f(iterations, queue, static_cast(const_cast *>(&func)), call_func_void_size_t); 48 | } 49 | 50 | void dispatch_async(dispatch_queue_t queue, const std::function &func) 51 | { 52 | std::function * func_ptr = new std::function(func); 53 | 54 | dispatch_async_f(queue, static_cast(func_ptr), call_funcptr_void_void); 55 | } 56 | void dispatch_sync(dispatch_queue_t queue, const std::function &func) 57 | { 58 | dispatch_sync_f(queue, static_cast(const_cast *>(&func)), call_func_void_void); 59 | } 60 | 61 | void dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, const std::function &func) 62 | { 63 | std::function * func_ptr = new std::function(func); 64 | 65 | dispatch_group_async_f(group, queue, static_cast(func_ptr), call_funcptr_void_void); 66 | } 67 | void dispatch_group_notify(dispatch_group_t group, dispatch_queue_t queue, const std::function &func) 68 | { 69 | std::function * func_ptr = new std::function(func); 70 | 71 | dispatch_group_notify_f(group, queue, static_cast(func_ptr), call_funcptr_void_void); 72 | } 73 | 74 | void dispatch_once(dispatch_once_t * predicate, const std::function &func) 75 | { 76 | dispatch_once_f(predicate, static_cast(const_cast *>(&func)), call_funcptr_void_void); 77 | } 78 | 79 | queue::queue() : priQueue(nullptr) 80 | { 81 | } 82 | 83 | queue::queue(const std::string &label, const attr attr) 84 | { 85 | static const std::unordered_map mapAttr = { 86 | {attr::SERIAL, DISPATCH_QUEUE_SERIAL}, 87 | {attr::CONCURRENT, DISPATCH_QUEUE_CONCURRENT} 88 | }; 89 | 90 | this->priQueue = dispatch_queue_create(label.c_str(), mapAttr.at(attr)); 91 | } 92 | 93 | queue::queue(const queue &q) 94 | { 95 | this->priQueue = q.priQueue; 96 | 97 | dispatch_retain(this->priQueue); 98 | } 99 | 100 | queue::queue(queue &&q) 101 | { 102 | this->priQueue = q.priQueue; 103 | 104 | q.priQueue = nullptr; 105 | } 106 | 107 | queue::~queue() 108 | { 109 | if (this->priQueue != nullptr) { 110 | dispatch_release(this->priQueue); 111 | } 112 | } 113 | 114 | 115 | std::string queue::label() 116 | { 117 | return dispatch_queue_get_label(this->priQueue); 118 | } 119 | 120 | queue queue::globalQueue(const priority priority) 121 | { 122 | static const std::unordered_map mapPriority = { 123 | {priority::HIGH, DISPATCH_QUEUE_PRIORITY_HIGH}, 124 | {priority::DEFAULT, DISPATCH_QUEUE_PRIORITY_DEFAULT}, 125 | {priority::LOW, DISPATCH_QUEUE_PRIORITY_LOW}, 126 | {priority::BACKGROUND, DISPATCH_QUEUE_PRIORITY_BACKGROUND}, 127 | }; 128 | 129 | queue q; 130 | 131 | q.priQueue = dispatch_get_global_queue(mapPriority.at(priority), 0); 132 | 133 | return q; 134 | } 135 | 136 | queue queue::mainQueue() 137 | { 138 | queue q; 139 | 140 | q.priQueue = dispatch_get_main_queue(); 141 | 142 | return q; 143 | } 144 | 145 | void queue::apply(const size_t iterations, const std::function &func) 146 | { 147 | dispatch_apply(iterations, this->priQueue, func); 148 | } 149 | 150 | 151 | void queue::async(const std::function &func) 152 | { 153 | dispatch_async(this->priQueue, func); 154 | } 155 | 156 | void queue::sync(const std::function &func) 157 | { 158 | dispatch_sync(this->priQueue, func); 159 | } 160 | 161 | void queue::suspend() 162 | { 163 | dispatch_suspend(this->priQueue); 164 | } 165 | 166 | void queue::resume() 167 | { 168 | dispatch_resume(this->priQueue); 169 | } 170 | 171 | group::group() : priGroup(dispatch_group_create()) 172 | { 173 | } 174 | 175 | group::group(const group &grp) 176 | { 177 | this->priGroup = grp.priGroup; 178 | 179 | dispatch_retain(this->priGroup); 180 | } 181 | 182 | group::group(group &&grp) 183 | { 184 | this->priGroup = grp.priGroup; 185 | 186 | grp.priGroup = nullptr; 187 | } 188 | 189 | group::~group() 190 | { 191 | if (this->priGroup != nullptr) { 192 | dispatch_release(this->priGroup); 193 | } 194 | } 195 | 196 | void group::enter() 197 | { 198 | dispatch_group_enter(this->priGroup); 199 | } 200 | 201 | void group::leave() 202 | { 203 | dispatch_group_leave(this->priGroup); 204 | } 205 | 206 | long group::wait(dispatch_time_t timeout) 207 | { 208 | return dispatch_group_wait(this->priGroup, timeout); 209 | } 210 | 211 | void group::notify(queue &q, const std::function &func) 212 | { 213 | dispatch_group_notify(this->priGroup, q.priQueue, func); 214 | } 215 | 216 | void group::async(queue &q, const std::function &func) 217 | { 218 | dispatch_group_async(this->priGroup, q.priQueue, func); 219 | } 220 | 221 | semaphore::semaphore() : priSemaphore(dispatch_semaphore_create(0)) 222 | { 223 | } 224 | 225 | semaphore::semaphore(long count) : priSemaphore(dispatch_semaphore_create(count)) 226 | { 227 | } 228 | 229 | semaphore::semaphore(const semaphore &sema) 230 | { 231 | this->priSemaphore = sema.priSemaphore; 232 | 233 | dispatch_retain(this->priSemaphore); 234 | } 235 | 236 | semaphore::semaphore(semaphore &&sema) 237 | { 238 | this->priSemaphore = sema.priSemaphore; 239 | 240 | sema.priSemaphore = nullptr; 241 | } 242 | 243 | semaphore::~semaphore() 244 | { 245 | if (this->priSemaphore != nullptr) { 246 | dispatch_release(this->priSemaphore); 247 | } 248 | } 249 | 250 | long semaphore::signal() 251 | { 252 | return dispatch_semaphore_signal(this->priSemaphore); 253 | } 254 | 255 | long semaphore::wait(dispatch_time_t timeout) 256 | { 257 | return dispatch_semaphore_wait(this->priSemaphore, timeout); 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /dispatch-c++.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace dispatch { 6 | 7 | void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, const std::function &func); 8 | 9 | void dispatch_apply(size_t iterations, dispatch_queue_t queue, const std::function &func); 10 | 11 | void dispatch_async(dispatch_queue_t queue, const std::function &func); 12 | void dispatch_sync(dispatch_queue_t queue, const std::function &func); 13 | 14 | void dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, const std::function &func); 15 | void dispatch_group_notify(dispatch_group_t group, dispatch_queue_t queue, const std::function &func); 16 | 17 | void dispatch_once(dispatch_once_t * predicate, const std::function &func); 18 | 19 | class queue { 20 | friend class group; 21 | public: 22 | enum class attr { 23 | SERIAL, CONCURRENT, 24 | }; 25 | 26 | queue(); 27 | queue(const std::string &label, const attr attr); 28 | queue(const queue &q); 29 | queue(queue &&q); 30 | 31 | virtual ~queue(); 32 | 33 | std::string label(); 34 | 35 | enum class priority { 36 | HIGH, DEFAULT, LOW, BACKGROUND, 37 | }; 38 | 39 | static queue globalQueue(const priority priority); // assert flags == 0 now 40 | 41 | static queue mainQueue(); 42 | 43 | void apply(const size_t iterations, const std::function &func); 44 | 45 | void async(const std::function &func); 46 | void sync(const std::function &func); 47 | 48 | void suspend(); 49 | void resume(); 50 | 51 | private: 52 | dispatch_queue_t priQueue; 53 | }; 54 | 55 | class group { 56 | public: 57 | group(); 58 | group(const group &grp); 59 | group(group &&grp); 60 | 61 | virtual ~group(); 62 | 63 | void enter(); 64 | void leave(); 65 | 66 | long wait(dispatch_time_t timeout); 67 | 68 | void notify(queue &q, const std::function &func); 69 | 70 | void async(queue &q, const std::function &func); 71 | 72 | private: 73 | dispatch_group_t priGroup; 74 | }; 75 | 76 | class semaphore { 77 | public: 78 | semaphore(); 79 | semaphore(long count); 80 | semaphore(const semaphore &sema); 81 | semaphore(semaphore &&sema); 82 | 83 | virtual ~semaphore(); 84 | 85 | long signal(); 86 | long wait(dispatch_time_t timeout); 87 | 88 | private: 89 | dispatch_semaphore_t priSemaphore; 90 | }; 91 | } 92 | -------------------------------------------------------------------------------- /libdispatch-c++.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "follow_symlinks": true, 5 | "path": ".", 6 | } 7 | ], 8 | "settings": 9 | { 10 | "tab_size" : 8, 11 | }, 12 | "build_systems": [ 13 | { 14 | "name": "libdispatch-c++", 15 | "cmd": ["make", "test"], 16 | "working_dir": "${project_path:${folder}}", 17 | 18 | "variants": [ 19 | { 20 | "name": "clean", 21 | "cmd": ["make", "clean"], 22 | } 23 | ] 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /test_main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "dispatch-c++.h" 6 | 7 | void test_dispatch_queue() 8 | { 9 | std::atomic a; 10 | 11 | a = 0; 12 | 13 | dispatch::queue queue = dispatch::queue::globalQueue(dispatch::queue::priority::DEFAULT); 14 | 15 | queue.apply(100, [&a] (size_t idx) { 16 | a += idx + 1; 17 | }); 18 | 19 | assert(a == 5050); 20 | } 21 | 22 | void test_dispatch_group() 23 | { 24 | int a = 0; 25 | 26 | dispatch::group group; 27 | dispatch::queue queue("main_test.dispatch_async", dispatch::queue::attr::SERIAL); 28 | 29 | for (int i = 1; i <= 100; i++) { 30 | group.async(queue, [=, &a] () { 31 | a += i; 32 | }); 33 | } 34 | 35 | group.wait(DISPATCH_TIME_FOREVER); 36 | 37 | assert(a == 5050); 38 | } 39 | 40 | int test_main(const int argc, const char * argv[], const char * envp[]) 41 | { 42 | test_dispatch_queue(); 43 | test_dispatch_group(); 44 | 45 | std::cout << "Success!" << std::endl; 46 | 47 | return 0; 48 | } 49 | --------------------------------------------------------------------------------