├── README.md ├── handlemap.h ├── simplelock.h ├── test.c ├── simplethread.h └── handlemap.c /README.md: -------------------------------------------------------------------------------- 1 | 这个数据结构可以帮助你把一组对象指针映射为一组数字 ID ,并提供读写安全的 API 。 2 | 3 | 把 handlemap.c 及 *.h 文件加入你的项目即可使用。 4 | 5 | 细节见: http://blog.codingnow.com/2015/04/handlemap.html 6 | -------------------------------------------------------------------------------- /handlemap.h: -------------------------------------------------------------------------------- 1 | #ifndef HANDLE_MAP_H 2 | #define HANDLE_MAP_H 3 | 4 | typedef unsigned int handleid; 5 | 6 | struct handlemap; 7 | 8 | struct handlemap * handlemap_init(); 9 | void handlemap_exit(struct handlemap *); 10 | 11 | handleid handlemap_new(struct handlemap *, void *ud); 12 | void * handlemap_grab(struct handlemap *, handleid id); 13 | void * handlemap_release(struct handlemap *, handleid id); 14 | int handlemap_list(struct handlemap *, int n, handleid * result); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /simplelock.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_LOCK_H 2 | #define SIMPLE_LOCK_H 3 | 4 | #ifdef _MSC_VER 5 | 6 | #include 7 | #define inline __inline 8 | 9 | #define atom_cas_long(ptr, oval, nval) (InterlockedCompareExchange((LONG volatile *)ptr, nval, oval) == oval) 10 | #define atom_cas_pointer(ptr, oval, nval) (InterlockedCompareExchangePointer((PVOID volatile *)ptr, nval, oval) == oval) 11 | #define atom_inc(ptr) InterlockedIncrement((LONG volatile *)ptr) 12 | #define atom_dec(ptr) InterlockedDecrement((LONG volatile *)ptr) 13 | #define atom_sync() MemoryBarrier() 14 | #define atom_spinlock(ptr) while (InterlockedExchange((LONG volatile *)ptr , 1)) {} 15 | #define atom_spinunlock(ptr) InterlockedExchange((LONG volatile *)ptr, 0) 16 | 17 | #else 18 | 19 | #define atom_cas_long(ptr, oval, nval) __sync_bool_compare_and_swap(ptr, oval, nval) 20 | #define atom_cas_pointer(ptr, oval, nval) __sync_bool_compare_and_swap(ptr, oval, nval) 21 | #define atom_inc(ptr) __sync_add_and_fetch(ptr, 1) 22 | #define atom_dec(ptr) __sync_sub_and_fetch(ptr, 1) 23 | #define atom_sync() __sync_synchronize() 24 | #define atom_spinlock(ptr) while (__sync_lock_test_and_set(ptr,1)) {} 25 | #define atom_spinunlock(ptr) __sync_lock_release(ptr) 26 | 27 | #endif 28 | 29 | /* spin lock */ 30 | #define spin_lock(Q) atom_spinlock(&(Q)->lock) 31 | #define spin_unlock(Q) atom_spinunlock(&(Q)->lock) 32 | 33 | /* read write lock */ 34 | 35 | struct rwlock { 36 | int write; 37 | int read; 38 | }; 39 | 40 | static inline void 41 | rwlock_init(struct rwlock *lock) { 42 | lock->write = 0; 43 | lock->read = 0; 44 | } 45 | 46 | static inline void 47 | rwlock_rlock(struct rwlock *lock) { 48 | for (;;) { 49 | while(lock->write) { 50 | atom_sync(); 51 | } 52 | atom_inc(&lock->read); 53 | if (lock->write) { 54 | atom_dec(&lock->read); 55 | } else { 56 | break; 57 | } 58 | } 59 | } 60 | 61 | static inline void 62 | rwlock_wlock(struct rwlock *lock) { 63 | atom_spinlock(&lock->write); 64 | while(lock->read) { 65 | atom_sync(); 66 | } 67 | } 68 | 69 | static inline void 70 | rwlock_wunlock(struct rwlock *lock) { 71 | atom_spinunlock(&lock->write); 72 | } 73 | 74 | static inline void 75 | rwlock_runlock(struct rwlock *lock) { 76 | atom_dec(&lock->read); 77 | } 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Use following command to build the test: 4 | gcc handlemap.c test.c -lpthread 5 | 6 | Or VC: 7 | cl handlemap.c test.c 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "handlemap.h" 15 | #include "simplethread.h" 16 | 17 | #ifdef _MSC_VER 18 | 19 | #include 20 | 21 | static void 22 | usleep(int dummy) { 23 | Sleep(0); 24 | } 25 | 26 | #else 27 | 28 | #include 29 | #include 30 | 31 | #endif 32 | 33 | #define HANDLE_N 1000 34 | 35 | static handleid pool[HANDLE_N]; 36 | 37 | static void 38 | grab(struct handlemap *m, int thread) { 39 | int i; 40 | for (i=0;i 20 | 21 | #ifdef _MSC_VER 22 | #define INLINE __inline 23 | #else 24 | #define INLINE inline 25 | #endif 26 | 27 | static DWORD WINAPI 28 | thread_function(LPVOID lpParam) { 29 | struct thread * t = (struct thread *)lpParam; 30 | t->func(t->ud); 31 | return 0; 32 | } 33 | 34 | static void 35 | thread_join(struct thread * threads, int n) { 36 | int i; 37 | HANDLE *thread_handle = (HANDLE *)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,n*sizeof(HANDLE)); 38 | for (i=0;ievent = CreateEvent(NULL, FALSE, FALSE, NULL); 59 | } 60 | 61 | static INLINE void 62 | thread_event_release(struct thread_event *ev) { 63 | if (ev->event) { 64 | CloseHandle(ev->event); 65 | ev->event = NULL; 66 | } 67 | } 68 | 69 | static INLINE void 70 | thread_event_trigger(struct thread_event *ev) { 71 | SetEvent(ev->event); 72 | } 73 | 74 | static INLINE void 75 | thread_event_wait(struct thread_event *ev) { 76 | WaitForSingleObject(ev->event, INFINITE); 77 | } 78 | 79 | #else 80 | 81 | #include 82 | 83 | static void * 84 | thread_function(void * args) { 85 | struct thread * t = (struct thread *)args; 86 | t->func(t->ud); 87 | return NULL; 88 | } 89 | 90 | static void 91 | thread_join(struct thread *threads, int n) { 92 | pthread_t pid[n]; 93 | int i; 94 | for (i=0;imutex, NULL); 114 | pthread_cond_init(&ev->cond, NULL); 115 | ev->flag = 0; 116 | } 117 | 118 | static inline void 119 | thread_event_release(struct thread_event *ev) { 120 | pthread_mutex_destroy(&ev->mutex); 121 | pthread_cond_destroy(&ev->cond); 122 | } 123 | 124 | static inline void 125 | thread_event_trigger(struct thread_event *ev) { 126 | pthread_mutex_lock(&ev->mutex); 127 | ev->flag = 1; 128 | pthread_mutex_unlock(&ev->mutex); 129 | pthread_cond_signal(&ev->cond); 130 | } 131 | 132 | static inline void 133 | thread_event_wait(struct thread_event *ev) { 134 | pthread_mutex_lock(&ev->mutex); 135 | 136 | while (!ev->flag) 137 | pthread_cond_wait(&ev->cond, &ev->mutex); 138 | 139 | ev->flag = 0; 140 | 141 | pthread_mutex_unlock(&ev->mutex); 142 | } 143 | 144 | #endif 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /handlemap.c: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015 codingnow.com 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | 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, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | */ 24 | 25 | #include "handlemap.h" 26 | #include "simplelock.h" 27 | 28 | #include 29 | #include 30 | 31 | // must be pow of 2 32 | #define INIT_SLOTS 16 33 | 34 | struct handleslot { 35 | handleid id; 36 | int ref; 37 | void * ud; 38 | }; 39 | 40 | struct handlemap { 41 | handleid lastid; 42 | struct rwlock lock; 43 | int cap; 44 | int n; 45 | struct handleslot * slot; 46 | }; 47 | 48 | struct handlemap * 49 | handlemap_init() { 50 | struct handlemap * m = (struct handlemap *)malloc(sizeof(*m)); 51 | if (m == NULL) 52 | return NULL; 53 | m->lastid = 0; 54 | rwlock_init(&m->lock); 55 | m->cap = INIT_SLOTS; 56 | m->n = 0; 57 | m->slot = (struct handleslot *)calloc(m->cap, sizeof(*m->slot)); 58 | if (m->slot == NULL) { 59 | free(m); 60 | return NULL; 61 | } 62 | return m; 63 | } 64 | 65 | void 66 | handlemap_exit(struct handlemap *m) { 67 | if (m) { 68 | free(m->slot); 69 | free(m); 70 | } 71 | } 72 | 73 | static struct handlemap * 74 | expand_map(struct handlemap *m) { 75 | int i,cap = m->cap; 76 | struct handleslot * nslot; 77 | nslot = (struct handleslot *)calloc(cap * 2, sizeof(*nslot)); 78 | if (nslot == NULL) { 79 | return NULL; 80 | } 81 | for (i=0;islot[i]; 83 | struct handleslot * ns = &nslot[os->id & (cap * 2 -1)]; 84 | *ns = *os; 85 | } 86 | free(m->slot); 87 | m->slot = nslot; 88 | m->cap = cap * 2; 89 | return m; 90 | } 91 | 92 | handleid 93 | handlemap_new(struct handlemap *m, void *ud) { 94 | int i; 95 | if (ud == NULL) 96 | return 0; 97 | rwlock_wlock(&m->lock); 98 | if (m->n >= m->cap * 3 / 4) { 99 | if (expand_map(m) == NULL) { 100 | // memory overflow 101 | rwlock_wunlock(&m->lock); 102 | return 0; 103 | } 104 | } 105 | 106 | for (i=0;;i++) { 107 | struct handleslot *slot; 108 | handleid id = ++m->lastid; 109 | if (id == 0) { 110 | // 0 is reserved for invalid id 111 | id = ++m->lastid; 112 | } 113 | slot = &m->slot[id & (m->cap - 1)]; 114 | if (slot->id) 115 | continue; 116 | slot->id = id; 117 | slot->ref = 1; 118 | slot->ud = ud; 119 | ++m->n; 120 | 121 | rwlock_wunlock(&m->lock); 122 | return id; 123 | } 124 | } 125 | 126 | static void * 127 | release_ref(struct handlemap *m, handleid id) { 128 | struct handleslot * slot; 129 | void * ud = NULL; 130 | if (id == 0) 131 | return NULL; 132 | rwlock_rlock(&m->lock); 133 | slot = &m->slot[id & (m->cap - 1)]; 134 | if (slot->id != id) { 135 | rwlock_runlock(&m->lock); 136 | return NULL; 137 | } 138 | if (atom_dec(&slot->ref) <= 0) { 139 | ud = slot->ud; 140 | } 141 | rwlock_runlock(&m->lock); 142 | return ud; 143 | } 144 | 145 | static void * 146 | try_delete(struct handlemap *m, handleid id) { 147 | struct handleslot * slot; 148 | void * ud; 149 | if (id == 0) 150 | return NULL; 151 | rwlock_wlock(&m->lock); 152 | slot = &m->slot[id & (m->cap - 1)]; 153 | if (slot->id != id) { 154 | rwlock_wunlock(&m->lock); 155 | return NULL; 156 | } 157 | if (slot->ref > 0) { 158 | rwlock_wunlock(&m->lock); 159 | return NULL; 160 | } 161 | ud = slot->ud; 162 | slot->id = 0; 163 | --m->n; 164 | rwlock_wunlock(&m->lock); 165 | return ud; 166 | } 167 | 168 | void * 169 | handlemap_grab(struct handlemap *m, handleid id) { 170 | struct handleslot * slot; 171 | void * ud; 172 | if (id == 0) 173 | return NULL; 174 | rwlock_rlock(&m->lock); 175 | slot = &m->slot[id & (m->cap - 1)]; 176 | if (slot->id != id) { 177 | rwlock_runlock(&m->lock); 178 | return NULL; 179 | } 180 | atom_inc(&slot->ref); 181 | ud = slot->ud; 182 | rwlock_runlock(&m->lock); 183 | return ud; 184 | } 185 | 186 | void * 187 | handlemap_release(struct handlemap *m, handleid id) { 188 | if (release_ref(m, id)) { 189 | return try_delete(m, id); 190 | } else { 191 | return NULL; 192 | } 193 | } 194 | 195 | int 196 | handlemap_list(struct handlemap *m, int n, handleid * result) { 197 | int i,t=0; 198 | rwlock_rlock(&m->lock); 199 | for (i=0;t < n && icap;i++) { 200 | struct handleslot *slot = &m->slot[i]; 201 | if (slot->id == 0) 202 | continue; 203 | result[t] = slot->id; 204 | ++t; 205 | } 206 | 207 | t=m->n; 208 | rwlock_runlock(&m->lock); 209 | return t; 210 | } 211 | --------------------------------------------------------------------------------