static void start_node(void *context) { dispatch_group_t g = (dispatch_group_t)(context); size_t i; dispatch_queue_t this_q = dispatch_get_current_queue(); for (i = 0; i < COUNT; i++) { dispatch_group_async_f(g, this_q, NULL, work); } dispatch_group_async_f(g, this_q, NULL, node_done); //MU_MESSAGE("Spawned node %s", dispatch_queue_get_label(dispatch_get_current_queue())); }
void load_image(ConvertContext *context) { int result = RESULT_OK; char *error_desc; ExceptionType error_type; // wait for resources to be available dispatch_semaphore_wait(context->conv_semaphore, DISPATCH_TIME_FOREVER); // load image if (MagickReadImage(context->mw, context->src_path) == MagickFalse) { // deal with error error_desc = MagickGetException(context->mw, &error_type); asprintf(&context->results.message,"Error loading image (%s): %s\n",error_desc,context->src_path); error_desc = (char *)MagickRelinquishMemory(error_desc); result += RESULT_ERROR; } if (result == RESULT_OK) { // get image info context->hasAlphaChannel = MagickGetImageAlphaChannel(context->mw); if (context->hasAlphaChannel == MagickTrue) { context->imageWidth = MagickGetImageWidth(context->mw); context->imageHeight = MagickGetImageHeight(context->mw); // get pixel data context->pixel_count = context->imageWidth * context->imageHeight; context->pixels = malloc(context->pixel_count * sizeof(PixelData)); if (context->pixels == NULL) { asprintf(&context->results.message, "Error allocating memory for pixel data: %s\n",context->src_path); result += RESULT_ERROR; } else { if (MagickExportImagePixels(context->mw, 0, 0, context->imageWidth, context->imageHeight, "ARGB", CharPixel, context->pixels) == MagickFalse) { error_desc = MagickGetException(context->mw, &error_type); asprintf(&context->results.message, "Error exporting pixel data (%s): %s\n",error_desc,context->src_path); error_desc = (char *)MagickRelinquishMemory(error_desc); result += RESULT_ERROR; } } } } if (result != RESULT_OK) { // clean up mess context->results.result = result; dispatch_group_async_f(context->conv_group, dispatch_get_main_queue(), context, (void (*)(void *))finish_image); } else { // move to next step dispatch_group_async_f(context->conv_group, context->conv_queue, context, (void (*)(void *))conv_image); } }
static void do_test(void) { size_t i; char buf[1000]; dispatch_group_t g = dispatch_group_create(); for (i = 0; i < QUEUES; i++) { #ifdef WIN32 _snprintf(buf, sizeof(buf), "com.example.memoryload-node#%ld", i); #else snprintf(buf, sizeof(buf), "com.example.memoryload-node#%ld", (long int)i); #endif queues[i] = dispatch_queue_create(buf, NULL); dispatch_suspend(queues[i]); } for (i = 0; i < QUEUES; i++) { dispatch_group_async_f(g, queues[i], g, start_node); } dispatch_group_notify_f(g, dispatch_get_main_queue(), NULL, collect); for (i = 0; i < QUEUES; i++) { dispatch_resume(queues[i]); dispatch_release(queues[i]); } }
void group::async( operation *r, const queue &q ) { dispatch_queue_t nat_q = (dispatch_queue_t)q.native(); XDISPATCH_ASSERT( nat_q ); dispatch_group_async_f( m_native, nat_q, r, _xdispatch_run_operation ); }
void ISPCLaunch(void *func, void *data) { if (!initialized) { fprintf(stderr, "You must call TasksInit() before launching tasks.\n"); exit(1); } TaskInfo *ti = new TaskInfo; ti->func = func; ti->data = data; dispatch_group_async_f(gcdGroup, gcdQueue, ti, lRunTask); }
void save_image(ConvertContext *context) { int result = RESULT_OK; char *error_desc; ExceptionType error_type; // get pixel data if (context->hasAlphaChannel == MagickTrue) { if (MagickImportImagePixels(context->mw, 0, 0, context->imageWidth, context->imageHeight, "ARGB", CharPixel, context->pixels) == MagickFalse) { error_desc = MagickGetException(context->mw, &error_type); asprintf(&context->results.message, "Error exporting pixel data (%s): %s\n",error_desc,context->src_path); error_desc = (char *)MagickRelinquishMemory(error_desc); result += RESULT_ERROR; } } // convert image to PNG if (result == RESULT_OK) { if (MagickSetImageFormat(context->mw,"PNG") == MagickFalse) { error_desc = MagickGetException(context->mw, &error_type); asprintf(&context->results.message,"Error converting image (%s): %s\n",error_desc,context->src_path); error_desc = (char *)MagickRelinquishMemory(error_desc); result += RESULT_ERROR; } } // activate/deactivate alpha channel MagickSetImageAlphaChannel(context->mw, (context->results.alpha_type == ALPHA_TYPE_NONE ? DeactivateAlphaChannel : ActivateAlphaChannel)); // make sure image is saved as RGB and not crunched down to grayscale MagickSetType(context->mw, (context->results.alpha_type == ALPHA_TYPE_NONE ? TrueColorType : TrueColorMatteType)); // save image to disk if (result == RESULT_OK) { if (MagickWriteImage(context->mw, context->dst_path) == MagickFalse) { error_desc = MagickGetException(context->mw, &error_type); asprintf(&context->results.message, "Error saving image (%s): %s\n",error_desc,context->dst_path); error_desc = (char *)MagickRelinquishMemory(error_desc); result += RESULT_ERROR; } } if (result == RESULT_OK && context->options.delete_original != 0) { if (unlink(context->src_path) == -1) { asprintf(&context->results.message, "Unable to delete original image (%s): %s\n", strerror(errno), context->src_path); result += RESULT_ERROR; } } // cleanup and report results context->results.result = result; dispatch_group_async_f(context->conv_group, dispatch_get_main_queue(), context, (void (*)(void *))finish_image); }
void dispatch_group_function() { long res; dispatch_group_t group; MU_BEGIN_TEST(dispatch_group_function); group = create_group(100, 0); MU_ASSERT_NOT_NULL(group); dispatch_group_wait(group, DISPATCH_TIME_FOREVER); // should be OK to re-use a group dispatch_group_async_f(group, dispatch_get_global_queue(0, 0), 0, foo); dispatch_group_wait(group, DISPATCH_TIME_FOREVER); dispatch_release(group); group = NULL; group = create_group(3, 7); MU_ASSERT_NOT_NULL(group); res = dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5ull * NSEC_PER_SEC)); MU_ASSERT_EQUAL(!res, 0); // retry after timeout (this time succeed) res = dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5ull * NSEC_PER_SEC)); MU_ASSERT_EQUAL(res, 0); dispatch_release(group); group = NULL; group = create_group(100, 0); MU_ASSERT_NOT_NULL(group); dispatch_group_notify_f(group, dispatch_get_main_queue(), 0, group_notify); dispatch_release(group); group = NULL; dispatch_main(); MU_FAIL("Should never reach this"); MU_END_TEST }
static VALUE rb_queue_dispatch_async(VALUE self, SEL sel, int argc, VALUE *argv) { rb_vm_block_t *block = get_prepared_block(); VALUE group; rb_scan_args(argc, argv, "01", &group); if (group != Qnil) { Check_Group(group); dispatch_group_async_f(RGroup(group)->group, RQueue(self)->queue, (void *)block, rb_block_dispatcher); } else { dispatch_async_f(RQueue(self)->queue, (void *)block, rb_block_dispatcher); } return Qnil; }
static dispatch_group_t create_group(size_t count, int delay) { size_t i; int* param; dispatch_group_t group = dispatch_group_create(); for (i = 0; i < count; ++i) { dispatch_queue_t queue = dispatch_queue_create("foo", NULL); param = (int*)malloc(sizeof(int)); *param = delay; MU_ASSERT_NOT_NULL(queue); MU_ASSERT_NOT_NULL(param); dispatch_group_async_f(group, queue, param, work); dispatch_release(queue); } return group; }
void EnqueueTasks(const vector<Task *> &tasks) { if (PbrtOptions.nCores == 1) { for (unsigned int i = 0; i < tasks.size(); ++i) tasks[i]->Run(); return; } #ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH for (uint32_t i = 0; i < tasks.size(); ++i) dispatch_group_async_f(gcdGroup, gcdQueue, tasks[i], lRunTask); #else if (!threads) TasksInit(); { MutexLock lock(*taskQueueMutex); for (unsigned int i = 0; i < tasks.size(); ++i) taskQueue.push_back(tasks[i]); } tasksRunningCondition.Lock(); numUnfinishedTasks += tasks.size(); tasksRunningCondition.Unlock(); workerSemaphore.Post(tasks.size()); #endif }
void EnqueueTasks(const vector<Task *> &tasks) { #ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH static bool oneThread = (getenv("PBRT_NTHREADS") && atoi(getenv("PBRT_NTHREADS")) == 1); for (u_int i = 0; i < tasks.size(); ++i) if (oneThread) dispatch_sync_f(gcdQueue, tasks[i], lRunTask); else dispatch_group_async_f(gcdGroup, gcdQueue, tasks[i], lRunTask); #else if (!threads) TasksInit(); { MutexLock lock(*taskQueueMutex); for (unsigned int i = 0; i < tasks.size(); ++i) taskQueue.push_back(tasks[i]); } tasksRunningCondition.Lock(); numUnfinishedTasks += tasks.size(); tasksRunningCondition.Unlock(); workerSemaphore.Post(tasks.size()); #endif }
void asyncDispatch(dispatch_group_t g, void *args, dispatch_function_t func) { return dispatch_group_async_f(g, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), args, func); }
void process_image(ConvertContext *context) { context->results.result = RESULT_OK; context->mw = NewMagickWand(); dispatch_group_async_f(context->conv_group, context->load_queue, context, (void (*)(void *))load_image); }
void conv_image(ConvertContext *context) { int result = RESULT_OK; BackgroundMetric *backgrounds = NULL; int bkgnd_size = BKGND_GROWTH; int bkgnd_count; int bkgnd_index; int bkgnd_selected = BKGND_NONE; double bkgnd_ratio = 0.0; unsigned long bkgnd_pixels; unsigned long pixel_index; int red; int grn; int blu; int alp; int inv; int bkgnd_red; int bkgnd_grn; int bkgnd_blu; int alpha_other = 0; int alpha_match = 0; int alpha_marginal = 0; int alpha_type = context->options.manual_alpha; // defaults to ALPHA_TYPE_UNKNOWN // check alpha if (result == RESULT_OK && context->hasAlphaChannel == MagickTrue && (alpha_type == ALPHA_TYPE_UNKNOWN || alpha_type == ALPHA_TYPE_ASSOCIATED)) { // allocate buffer for background metrics backgrounds = malloc(sizeof(BackgroundMetric) * bkgnd_size); if (backgrounds == NULL) { asprintf(&context->results.message, "Error allocating memory for background metrics"); result += RESULT_ERROR; } // load starting background metrics if (result == RESULT_OK) { backgrounds[BKGND_BLACK].red = 0; backgrounds[BKGND_BLACK].grn = 0; backgrounds[BKGND_BLACK].blu = 0; backgrounds[BKGND_BLACK].count = 0; backgrounds[BKGND_WHITE].red = 255; backgrounds[BKGND_WHITE].grn = 255; backgrounds[BKGND_WHITE].blu = 255; backgrounds[BKGND_WHITE].count = 0; bkgnd_count = 2; } // analyze image // get background color if (result == RESULT_OK) { bkgnd_pixels = 0; pixel_index = 0; while (result == RESULT_OK && pixel_index < context->pixel_count) { red = context->pixels[pixel_index].red; grn = context->pixels[pixel_index].grn; blu = context->pixels[pixel_index].blu; alp = context->pixels[pixel_index].alp; // transparent pixels only... if (alp == 0) { bkgnd_pixels++; // look for color in metrics for (bkgnd_index = 0; bkgnd_index < bkgnd_count; bkgnd_index++) { if (red == backgrounds[bkgnd_index].red && grn == backgrounds[bkgnd_index].grn && blu == backgrounds[bkgnd_index].blu) { backgrounds[bkgnd_index].count++; break; } } if (bkgnd_index == bkgnd_count) { // add another metric if (bkgnd_count == bkgnd_size) { bkgnd_size += BKGND_GROWTH; backgrounds = realloc(backgrounds, sizeof(BackgroundMetric) * bkgnd_size); if (backgrounds == NULL) { asprintf(&context->results.message,"Error allocating memory for background metrics"); result += RESULT_ERROR; break; } } backgrounds[bkgnd_index].red = red; backgrounds[bkgnd_index].grn = grn; backgrounds[bkgnd_index].blu = blu; backgrounds[bkgnd_index].count = 1; bkgnd_count++; } } pixel_index++; } } // find background color in metrics if (result == RESULT_OK) { for (bkgnd_index = 0; bkgnd_index < bkgnd_count; bkgnd_index++) { if (backgrounds[bkgnd_index].count > (bkgnd_selected == BKGND_NONE ? 0 : backgrounds[bkgnd_selected].count)) bkgnd_selected = bkgnd_index; } // make sure the selected color wins by a good margin if (bkgnd_selected != BKGND_NONE) { bkgnd_ratio = (double)backgrounds[bkgnd_selected].count / (double)bkgnd_pixels; if (bkgnd_ratio < context->options.bkgnd_ratio && !context->options.force) { asprintf(&context->results.message, "Inconsistent background color (ratio at %g; should be %g or greater): %s\n",bkgnd_ratio, context->options.bkgnd_ratio, context->src_path); result += RESULT_WARNING; } } } if (result == RESULT_OK && bkgnd_selected != BKGND_NONE) { // check translucent pixels pixel_index = 0; while (pixel_index < context->pixel_count) { alp = context->pixels[pixel_index].alp; if (alp > 0 && alp < 255) { red = context->pixels[pixel_index].red; grn = context->pixels[pixel_index].grn; blu = context->pixels[pixel_index].blu; inv = 255 - alp; red = red - (int)roundf((float)(inv * backgrounds[bkgnd_selected].red)/255.0); grn = grn - (int)roundf((float)(inv * backgrounds[bkgnd_selected].grn)/255.0); blu = blu - (int)roundf((float)(inv * backgrounds[bkgnd_selected].blu)/255.0); // check range of pixel if (red <= alp && red >= 0 && blu <= alp && blu >= 0 && grn <= alp && grn >= 0) { alpha_match++; } else if (red <= alp + 1 && red >= -1 && blu <= alp + 1 && blu >= -1 && grn <= alp + 1 && grn >= -1) { alpha_marginal++; } else { alpha_other++; } } pixel_index++; } // when associated alpha is specified, adjust pixel counts to make it happen if (alpha_type == ALPHA_TYPE_ASSOCIATED) { alpha_match = (alpha_match > 0 ? alpha_match : 1); alpha_marginal += alpha_other; alpha_other = 0; } // If all the translucent pixels fall within the proper range, then // this the alpha is likely pre-multiplied (associated) over background if (alpha_match > 0 && alpha_other == 0) { alpha_type = ALPHA_TYPE_ASSOCIATED; if (bkgnd_selected != BKGND_BLACK && bkgnd_selected != BKGND_WHITE) { if (!context->options.force) { asprintf(&context->results.message, "Invalid background - must be black or white (R:%hhu G:%hhu B:%hhu): %s\n", backgrounds[bkgnd_selected].red, backgrounds[bkgnd_selected].grn, backgrounds[bkgnd_selected].blu, context->src_path); result += RESULT_WARNING; } } } else { // straight (unassociated) alpha alpha_type = ALPHA_TYPE_UNASSOCIATED; } } if (result == RESULT_OK && (alpha_type == ALPHA_TYPE_ASSOCIATED)) { // correct image pixel_index = 0; while (result == RESULT_OK && pixel_index < context->pixel_count) { red = context->pixels[pixel_index].red; grn = context->pixels[pixel_index].grn; blu = context->pixels[pixel_index].blu; alp = context->pixels[pixel_index].alp; inv = 255 - alp; if (alp > 0 && alp < 255) { /* Standard image composition formula (foreground through a mask over a background) Comp = (Fg * A) + ((1 - A) * Bg) So here is how we would get the foreground back... Fg = (Comp - ((1 - A) * Bg)) / A */ if (bkgnd_selected == BKGND_BLACK) { // this one is easy... // Fg = Comp / A if (alpha_marginal != 0) { red = (red > alp ? alp : red); grn = (grn > alp ? alp : grn); blu = (blu > alp ? alp : blu); } if (red != 0) red = (int)roundf((float)(red * 255) / (float)alp); if (grn != 0) grn = (int)roundf((float)(grn * 255) / (float)alp); if (blu != 0) blu = (int)roundf((float)(blu * 255) / (float)alp); } else if (bkgnd_selected == BKGND_WHITE) { // much harder... // Fg = (Comp - (1 - A)) / A if (alpha_marginal != 0) { red = (red < inv ? inv : red); grn = (grn < inv ? inv : grn); blu = (blu < inv ? inv : blu); } if (red != 255) red = (int)roundf((float)((red - inv) * 255) / (float)alp); if (grn != 255) grn = (int)roundf((float)((grn - inv) * 255) / (float)alp); if (blu != 255) blu = (int)roundf((float)((blu - inv) * 255) / (float)alp); } else { // way harder! (not sure if this really works) // Fg = (Comp - ((1 - A) * Bg)) / A bkgnd_red = (int)roundf((float)(inv * backgrounds[bkgnd_selected].red)/255.0); bkgnd_grn = (int)roundf((float)(inv * backgrounds[bkgnd_selected].grn)/255.0); bkgnd_blu = (int)roundf((float)(inv * backgrounds[bkgnd_selected].blu)/255.0); if (alpha_marginal != 0) { red = (red < bkgnd_red ? bkgnd_red : red); grn = (grn < bkgnd_grn ? bkgnd_grn : grn); blu = (blu < bkgnd_blu ? bkgnd_blu : blu); } red = (int)roundf((float)((red - bkgnd_red) * 255) / (float)alp); grn = (int)roundf((float)((grn - bkgnd_grn) * 255) / (float)alp); blu = (int)roundf((float)((blu - bkgnd_blu) * 255) / (float)alp); } context->pixels[pixel_index].red = red; context->pixels[pixel_index].blu = blu; context->pixels[pixel_index].grn = grn; } pixel_index++; } } } if (alpha_type == ALPHA_TYPE_UNKNOWN || context->hasAlphaChannel == MagickFalse) alpha_type = ALPHA_TYPE_NONE; // fill in results context->results.alpha_type = alpha_type; context->results.bkgnd_type = (bkgnd_selected == BKGND_NONE || bkgnd_selected == BKGND_BLACK || bkgnd_selected == BKGND_WHITE ? bkgnd_selected : BKGND_OTHER); context->results.bkgnd_ratio = bkgnd_ratio; context->results.bkgnd_red = (bkgnd_selected == BKGND_NONE ? 0 : backgrounds[bkgnd_selected].red); context->results.bkgnd_grn = (bkgnd_selected == BKGND_NONE ? 0 : backgrounds[bkgnd_selected].grn); context->results.bkgnd_blu = (bkgnd_selected == BKGND_NONE ? 0 : backgrounds[bkgnd_selected].blu); if (backgrounds != NULL) { free(backgrounds); } if (result != RESULT_OK || context->options.dry_run != 0) { // clean up mess context->results.result = result; dispatch_group_async_f(context->conv_group, dispatch_get_main_queue(), context, (void (*)(void *))finish_image); } else { // move to next step dispatch_group_async_f(context->conv_group, context->save_queue, context, (void (*)(void *))save_image); } }