diff options
| author | enricotenuti <tenutz_27@outlook.it> | 2024-09-24 16:45:42 +0200 |
|---|---|---|
| committer | enricotenuti <tenutz_27@outlook.it> | 2024-09-24 16:45:42 +0200 |
| commit | c299466bfa9a9a172e1cc021cf7b9ed6a4093888 (patch) | |
| tree | 1c643f7d8f5f73be790797491ac0e684521d55e8 | |
| parent | 1a092414735f244bffa3c6878e57463b7dd1e9ba (diff) | |
| download | nissy-core-c299466bfa9a9a172e1cc021cf7b9ed6a4093888.tar.gz nissy-core-c299466bfa9a9a172e1cc021cf7b9ed6a4093888.zip | |
Fixed multithread search, todo multiple scramble memory release
| -rw-r--r-- | src/solvers/h48/thread.h | 158 |
1 files changed, 66 insertions, 92 deletions
diff --git a/src/solvers/h48/thread.h b/src/solvers/h48/thread.h index 1eade29..155bc6a 100644 --- a/src/solvers/h48/thread.h +++ b/src/solvers/h48/thread.h | |||
| @@ -5,32 +5,31 @@ | |||
| 5 | #include <stdlib.h> | 5 | #include <stdlib.h> |
| 6 | 6 | ||
| 7 | #define MAX_QUEUE_SIZE 500 | 7 | #define MAX_QUEUE_SIZE 500 |
| 8 | |||
| 9 | typedef struct | 8 | typedef struct |
| 10 | { | 9 | { |
| 11 | dfsarg_solveh48_t *tasks[MAX_QUEUE_SIZE]; | 10 | dfsarg_solveh48_t *tasks[MAX_QUEUE_SIZE]; |
| 12 | int front; | 11 | int front; |
| 13 | int rear; | 12 | int rear; |
| 14 | int tasks_count; | 13 | int tasks_count; |
| 14 | int active; | ||
| 15 | pthread_mutex_t mutex; | 15 | pthread_mutex_t mutex; |
| 16 | pthread_cond_t cond; | 16 | pthread_cond_t cond; |
| 17 | atomic_int active_tasks; | 17 | pthread_cond_t active_cond; |
| 18 | pthread_mutex_t active_tasks_mutex; | 18 | bool terminate; |
| 19 | pthread_cond_t active_tasks_cond; | ||
| 20 | } task_queue_t; | 19 | } task_queue_t; |
| 21 | 20 | ||
| 22 | STATIC void solve_h48_appendsolution_thread(dfsarg_solveh48_t *, task_queue_t *); | 21 | STATIC void solve_h48_appendsolution_thread(dfsarg_solveh48_t *, task_queue_t *); |
| 23 | STATIC void init_queue(task_queue_t *); | 22 | STATIC void init_queue(task_queue_t *); |
| 24 | STATIC void submit_task(task_queue_t *, dfsarg_solveh48_t *); | 23 | STATIC void submit_task(task_queue_t *, dfsarg_solveh48_t *); |
| 25 | STATIC void copy_queue(task_queue_t *, task_queue_t *, int); | 24 | STATIC void copy_queue(task_queue_t *, task_queue_t *, int, int64_t *); |
| 26 | STATIC dfsarg_solveh48_t *get_task(task_queue_t *); | ||
| 27 | STATIC void *start_thread(void *); | 25 | STATIC void *start_thread(void *); |
| 28 | STATIC int64_t solve_h48_bfs(dfsarg_solveh48_t *, task_queue_t *); | 26 | STATIC int64_t solve_h48_bfs(dfsarg_solveh48_t *, task_queue_t *); |
| 29 | STATIC int64_t solve_h48_single(dfsarg_solveh48_t *, task_queue_t *); | 27 | STATIC int64_t solve_h48_single(dfsarg_solveh48_t *, task_queue_t *); |
| 30 | STATIC int64_t solve_h48_parent(cube_t, int8_t, int8_t, int8_t, const void *, char *); | 28 | STATIC int64_t solve_h48_parent(cube_t, int8_t, int8_t, int8_t, const void *, char *); |
| 31 | 29 | ||
| 32 | STATIC void | 30 | STATIC void |
| 33 | solve_h48_appendsolution_thread(dfsarg_solveh48_t *arg, task_queue_t *tq){ | 31 | solve_h48_appendsolution_thread(dfsarg_solveh48_t *arg, task_queue_t *tq) |
| 32 | { | ||
| 34 | pthread_mutex_lock(&tq->mutex); | 33 | pthread_mutex_lock(&tq->mutex); |
| 35 | int strl; | 34 | int strl; |
| 36 | uint8_t invertedpremoves[MAXLEN]; | 35 | uint8_t invertedpremoves[MAXLEN]; |
| @@ -62,8 +61,10 @@ init_queue(task_queue_t *queue) | |||
| 62 | queue->front = 0; | 61 | queue->front = 0; |
| 63 | queue->rear = 0; | 62 | queue->rear = 0; |
| 64 | queue->tasks_count = 0; | 63 | queue->tasks_count = 0; |
| 64 | queue->active = 0; | ||
| 65 | pthread_mutex_init(&queue->mutex, NULL); | 65 | pthread_mutex_init(&queue->mutex, NULL); |
| 66 | pthread_cond_init(&queue->cond, NULL); | 66 | pthread_cond_init(&queue->cond, NULL); |
| 67 | pthread_cond_init(&queue->active_cond, NULL); | ||
| 67 | } | 68 | } |
| 68 | 69 | ||
| 69 | STATIC void | 70 | STATIC void |
| @@ -73,14 +74,13 @@ submit_task(task_queue_t *queue, dfsarg_solveh48_t *task) | |||
| 73 | queue->tasks[queue->rear] = task; | 74 | queue->tasks[queue->rear] = task; |
| 74 | queue->rear = (queue->rear + 1) % MAX_QUEUE_SIZE; | 75 | queue->rear = (queue->rear + 1) % MAX_QUEUE_SIZE; |
| 75 | queue->tasks_count++; | 76 | queue->tasks_count++; |
| 76 | pthread_cond_signal(&queue->cond); | 77 | pthread_cond_broadcast(&queue->cond); |
| 77 | pthread_mutex_unlock(&queue->mutex); | 78 | pthread_mutex_unlock(&queue->mutex); |
| 78 | } | 79 | } |
| 79 | 80 | ||
| 80 | STATIC void | 81 | STATIC void |
| 81 | copy_queue(task_queue_t *src, task_queue_t *dest, int depth) | 82 | copy_queue(task_queue_t *src, task_queue_t *dest, int depth, int64_t *nsols) |
| 82 | { | 83 | { |
| 83 | pthread_mutex_lock(&src->mutex); | ||
| 84 | pthread_mutex_lock(&dest->mutex); | 84 | pthread_mutex_lock(&dest->mutex); |
| 85 | for (int i = src->front; i != src->rear; i = (i + 1) % MAX_QUEUE_SIZE) | 85 | for (int i = src->front; i != src->rear; i = (i + 1) % MAX_QUEUE_SIZE) |
| 86 | { | 86 | { |
| @@ -93,46 +93,42 @@ copy_queue(task_queue_t *src, task_queue_t *dest, int depth) | |||
| 93 | dest->front = src->front; | 93 | dest->front = src->front; |
| 94 | dest->rear = src->rear; | 94 | dest->rear = src->rear; |
| 95 | dest->tasks_count = src->tasks_count; | 95 | dest->tasks_count = src->tasks_count; |
| 96 | pthread_mutex_unlock(&src->mutex); | 96 | dest->active = src->active; |
| 97 | pthread_cond_signal(&dest->cond); | 97 | pthread_cond_broadcast(&dest->cond); |
| 98 | pthread_mutex_unlock(&dest->mutex); | 98 | pthread_mutex_unlock(&dest->mutex); |
| 99 | } | 99 | } |
| 100 | STATIC dfsarg_solveh48_t * | 100 | |
| 101 | get_task(task_queue_t *queue) | ||
| 102 | { | ||
| 103 | pthread_mutex_lock(&queue->mutex); | ||
| 104 | while (queue->tasks_count == 0) | ||
| 105 | { | ||
| 106 | pthread_cond_wait(&queue->cond, &queue->mutex); | ||
| 107 | } | ||
| 108 | dfsarg_solveh48_t *task = queue->tasks[queue->front]; | ||
| 109 | queue->front = (queue->front + 1) % MAX_QUEUE_SIZE; | ||
| 110 | queue->tasks_count--; | ||
| 111 | pthread_mutex_unlock(&queue->mutex); | ||
| 112 | return task; | ||
| 113 | } | ||
| 114 | 101 | ||
| 115 | STATIC void * | 102 | STATIC void * |
| 116 | start_thread(void *arg) | 103 | start_thread(void *arg) |
| 117 | { | 104 | { |
| 118 | task_queue_t *queue = (task_queue_t *)arg; | 105 | task_queue_t *queue = (task_queue_t *)arg; |
| 119 | while (true) | 106 | while (1) { |
| 120 | { | 107 | pthread_mutex_lock(&queue->mutex); |
| 121 | dfsarg_solveh48_t *task = get_task(queue); | 108 | while (queue->tasks_count == 0 && !queue->terminate) { |
| 122 | if (task == NULL) | 109 | pthread_cond_wait(&queue->cond, &queue->mutex); |
| 123 | { | 110 | } |
| 111 | if (queue->tasks_count == 0 && queue->terminate) { | ||
| 112 | pthread_mutex_unlock(&queue->mutex); | ||
| 124 | break; | 113 | break; |
| 125 | } | 114 | } |
| 126 | solve_h48_single(task, queue); | ||
| 127 | free(task); | ||
| 128 | 115 | ||
| 129 | pthread_mutex_lock(&queue->active_tasks_mutex); | 116 | if (queue->tasks_count > 0) { |
| 130 | atomic_fetch_sub(&queue->active_tasks, 1); | 117 | dfsarg_solveh48_t *task = queue->tasks[queue->front]; |
| 131 | if (atomic_load(&queue->active_tasks) == 0) | 118 | queue->front = (queue->front + 1) % MAX_QUEUE_SIZE; |
| 132 | { | 119 | queue->tasks_count--; |
| 133 | pthread_cond_signal(&queue->active_tasks_cond); | 120 | queue->active++; |
| 121 | pthread_mutex_unlock(&queue->mutex); | ||
| 122 | |||
| 123 | solve_h48_single(task, queue); | ||
| 124 | |||
| 125 | pthread_mutex_lock(&queue->mutex); | ||
| 126 | queue->active--; | ||
| 127 | |||
| 128 | if(queue->tasks_count == 0 && queue->active == 0) | ||
| 129 | pthread_cond_signal(&queue->active_cond); | ||
| 134 | } | 130 | } |
| 135 | pthread_mutex_unlock(&queue->active_tasks_mutex); | 131 | pthread_mutex_unlock(&queue->mutex); |
| 136 | } | 132 | } |
| 137 | return NULL; | 133 | return NULL; |
| 138 | } | 134 | } |
| @@ -146,19 +142,16 @@ solve_h48_bfs(dfsarg_solveh48_t *arg_zero, task_queue_t *tq) | |||
| 146 | int depth = 0; | 142 | int depth = 0; |
| 147 | int nodes_at_current_depth = 1; | 143 | int nodes_at_current_depth = 1; |
| 148 | int nodes_at_next_depth = 0; | 144 | int nodes_at_next_depth = 0; |
| 149 | |||
| 150 | queue[rear++] = *arg_zero; | 145 | queue[rear++] = *arg_zero; |
| 151 | 146 | ||
| 152 | while (front < rear) | 147 | while (front < rear){ |
| 153 | { | ||
| 154 | dfsarg_solveh48_t arg = queue[front++]; | 148 | dfsarg_solveh48_t arg = queue[front++]; |
| 155 | nodes_at_current_depth--; | 149 | nodes_at_current_depth--; |
| 156 | 150 | ||
| 157 | if (*arg.nsols == arg.maxsolutions) | 151 | if (*arg.nsols == arg.maxsolutions) |
| 158 | return 1; | 152 | return 1; |
| 159 | 153 | ||
| 160 | if (issolved(arg.cube)) | 154 | if (issolved(arg.cube)){ |
| 161 | { | ||
| 162 | if (arg.nmoves + arg.npremoves != arg.depth) | 155 | if (arg.nmoves + arg.npremoves != arg.depth) |
| 163 | continue; | 156 | continue; |
| 164 | solve_h48_appendsolution(&arg); | 157 | solve_h48_appendsolution(&arg); |
| @@ -168,42 +161,32 @@ solve_h48_bfs(dfsarg_solveh48_t *arg_zero, task_queue_t *tq) | |||
| 168 | arg.nissbranch = MM_NORMAL; | 161 | arg.nissbranch = MM_NORMAL; |
| 169 | uint32_t allowed = allowednextmove_h48(arg.moves, arg.nmoves, arg.nissbranch); | 162 | uint32_t allowed = allowednextmove_h48(arg.moves, arg.nmoves, arg.nissbranch); |
| 170 | 163 | ||
| 171 | for (uint8_t m = 0; m < 18; m++) | 164 | for (uint8_t m = 0; m < 18; m++){ |
| 172 | { | 165 | if (allowed & (1 << m)){ |
| 173 | if (allowed & (1 << m)) | ||
| 174 | { | ||
| 175 | nextarg = arg; | 166 | nextarg = arg; |
| 176 | nextarg.nmoves = arg.nmoves + 1; | 167 | nextarg.nmoves = arg.nmoves + 1; |
| 177 | nextarg.moves[arg.nmoves] = m; | 168 | nextarg.moves[arg.nmoves] = m; |
| 178 | nextarg.cube = move(arg.cube, m); | 169 | nextarg.cube = move(arg.cube, m); |
| 179 | nextarg.inverse = premove(arg.inverse, m); | 170 | nextarg.inverse = premove(arg.inverse, m); |
| 180 | 171 | ||
| 181 | if (nextarg.nmoves == 2) | 172 | if (nextarg.nmoves == 2){ |
| 182 | { | ||
| 183 | dfsarg_solveh48_t *task = malloc(sizeof(dfsarg_solveh48_t)); | 173 | dfsarg_solveh48_t *task = malloc(sizeof(dfsarg_solveh48_t)); |
| 184 | *task = nextarg; | 174 | *task = nextarg; |
| 185 | submit_task(tq, task); | 175 | submit_task(tq, task); |
| 186 | } | 176 | } else { |
| 187 | else | ||
| 188 | { | ||
| 189 | queue[rear++] = nextarg; | 177 | queue[rear++] = nextarg; |
| 190 | nodes_at_next_depth++; | 178 | nodes_at_next_depth++; |
| 191 | } | 179 | } |
| 192 | } | 180 | } |
| 193 | } | 181 | } |
| 194 | 182 | if (nodes_at_current_depth == 0){ | |
| 195 | if (nodes_at_current_depth == 0) | ||
| 196 | { | ||
| 197 | depth++; | 183 | depth++; |
| 198 | nodes_at_current_depth = nodes_at_next_depth; | 184 | nodes_at_current_depth = nodes_at_next_depth; |
| 199 | nodes_at_next_depth = 0; | 185 | nodes_at_next_depth = 0; |
| 200 | } | 186 | } |
| 201 | if (depth == 2) | 187 | if (depth == 2) return 0; |
| 202 | { | ||
| 203 | return 0; | ||
| 204 | } | ||
| 205 | } | 188 | } |
| 206 | return 0; | 189 | return 1; |
| 207 | } | 190 | } |
| 208 | 191 | ||
| 209 | STATIC int64_t | 192 | STATIC int64_t |
| @@ -219,8 +202,7 @@ solve_h48_single(dfsarg_solveh48_t *arg, task_queue_t *tq) | |||
| 219 | if (solve_h48_stop(arg)) | 202 | if (solve_h48_stop(arg)) |
| 220 | return 0; | 203 | return 0; |
| 221 | 204 | ||
| 222 | if (issolved(arg->cube)) | 205 | if (issolved(arg->cube)){ |
| 223 | { | ||
| 224 | if (arg->nmoves + arg->npremoves != arg->depth) | 206 | if (arg->nmoves + arg->npremoves != arg->depth) |
| 225 | return 0; | 207 | return 0; |
| 226 | solve_h48_appendsolution_thread(arg, tq); | 208 | solve_h48_appendsolution_thread(arg, tq); |
| @@ -230,13 +212,10 @@ solve_h48_single(dfsarg_solveh48_t *arg, task_queue_t *tq) | |||
| 230 | nextarg = *arg; | 212 | nextarg = *arg; |
| 231 | ret = 0; | 213 | ret = 0; |
| 232 | uint32_t allowed; | 214 | uint32_t allowed; |
| 233 | if (arg->nissbranch & MM_INVERSE) | 215 | if (arg->nissbranch & MM_INVERSE){ |
| 234 | { | ||
| 235 | allowed = allowednextmove_h48(arg->premoves, arg->npremoves, arg->nissbranch); | 216 | allowed = allowednextmove_h48(arg->premoves, arg->npremoves, arg->nissbranch); |
| 236 | for (m = 0; m < 18; m++) | 217 | for (m = 0; m < 18; m++){ |
| 237 | { | 218 | if (allowed & (1 << m)){ |
| 238 | if (allowed & (1 << m)) | ||
| 239 | { | ||
| 240 | nextarg.npremoves = arg->npremoves + 1; | 219 | nextarg.npremoves = arg->npremoves + 1; |
| 241 | nextarg.premoves[arg->npremoves] = m; | 220 | nextarg.premoves[arg->npremoves] = m; |
| 242 | nextarg.inverse = move(arg->inverse, m); | 221 | nextarg.inverse = move(arg->inverse, m); |
| @@ -244,14 +223,10 @@ solve_h48_single(dfsarg_solveh48_t *arg, task_queue_t *tq) | |||
| 244 | ret += solve_h48_single(&nextarg, tq); | 223 | ret += solve_h48_single(&nextarg, tq); |
| 245 | } | 224 | } |
| 246 | } | 225 | } |
| 247 | } | 226 | } else { |
| 248 | else | ||
| 249 | { | ||
| 250 | allowed = allowednextmove_h48(arg->moves, arg->nmoves, arg->nissbranch); | 227 | allowed = allowednextmove_h48(arg->moves, arg->nmoves, arg->nissbranch); |
| 251 | for (m = 0; m < 18; m++) | 228 | for (m = 0; m < 18; m++){ |
| 252 | { | 229 | if (allowed & (1 << m)){ |
| 253 | if (allowed & (1 << m)) | ||
| 254 | { | ||
| 255 | nextarg.nmoves = arg->nmoves + 1; | 230 | nextarg.nmoves = arg->nmoves + 1; |
| 256 | nextarg.moves[arg->nmoves] = m; | 231 | nextarg.moves[arg->nmoves] = m; |
| 257 | nextarg.cube = move(arg->cube, m); | 232 | nextarg.cube = move(arg->cube, m); |
| @@ -303,12 +278,7 @@ solve_h48_parent( | |||
| 303 | task_queue_t nq; | 278 | task_queue_t nq; |
| 304 | init_queue(&nq); | 279 | init_queue(&nq); |
| 305 | 280 | ||
| 306 | atomic_store(&nq.active_tasks, 0); | 281 | for (int i = 0; i < THREADS; i++){ |
| 307 | pthread_mutex_init(&nq.active_tasks_mutex, NULL); | ||
| 308 | pthread_cond_init(&nq.active_tasks_cond, NULL); | ||
| 309 | |||
| 310 | for (int i = 0; i < THREADS; i++) | ||
| 311 | { | ||
| 312 | pthread_create(&threads[i], NULL, &start_thread, &nq); | 282 | pthread_create(&threads[i], NULL, &start_thread, &nq); |
| 313 | } | 283 | } |
| 314 | 284 | ||
| @@ -318,18 +288,22 @@ solve_h48_parent( | |||
| 318 | p_depth++) | 288 | p_depth++) |
| 319 | { | 289 | { |
| 320 | LOG("Found %" PRId64 " solutions, searching at depth %" PRId8 "\n", nsols, p_depth); | 290 | LOG("Found %" PRId64 " solutions, searching at depth %" PRId8 "\n", nsols, p_depth); |
| 321 | copy_queue(&q, &nq, p_depth); | 291 | copy_queue(&q, &nq, p_depth, &nsols); |
| 322 | pthread_mutex_lock(&nq.active_tasks_mutex); | 292 | |
| 323 | while (nq.active_tasks > 0) | 293 | pthread_mutex_lock(&nq.mutex); |
| 324 | { | 294 | while (nq.active > 0 || nq.tasks_count > 0) |
| 325 | pthread_cond_wait(&nq.active_tasks_cond, &nq.active_tasks_mutex); | 295 | pthread_cond_wait(&nq.active_cond, &nq.mutex); |
| 326 | } | 296 | pthread_mutex_unlock(&nq.mutex); |
| 327 | pthread_mutex_unlock(&nq.active_tasks_mutex); | ||
| 328 | } | 297 | } |
| 329 | for (int i = 0; i < THREADS; i++) | 298 | |
| 330 | { | 299 | pthread_mutex_lock(&nq.mutex); |
| 300 | nq.terminate = true; | ||
| 301 | pthread_cond_broadcast(&nq.cond); | ||
| 302 | pthread_mutex_unlock(&nq.mutex); | ||
| 303 | |||
| 304 | for (int i = 0; i < THREADS; i++){ | ||
| 331 | pthread_join(threads[i], NULL); | 305 | pthread_join(threads[i], NULL); |
| 332 | } | 306 | } |
| 333 | 307 | // fix memory release for multiple scrambles. | |
| 334 | return nsols; | 308 | return nsols; |
| 335 | } | 309 | } |
