Exemplo n.º 1
0
int main(int argc, char * argv[]) {
    utils::thread_pool thread_pool(2); 
    async_hello_world handler;
    server instance("127.0.0.1", "8000", handler, thread_pool);
    instance.run();
    return 0;
}
Exemplo n.º 2
0
int HostRender::run_noninteractive(RaytracingContext& context,
                                   PixelFuncRaw const& render_pixel, int kill_timeout_seconds)
{
    Image      frame_buffer(context.params.image_width, context.params.image_height);
    ThreadPool thread_pool(context.params.num_threads);
    std::vector<glm::ivec2> tile_idx;

    Timer timer;
    timer.start();
    context.scene->refresh_scene(context.params);
    launch(&frame_buffer, thread_pool, &context, &tile_idx, render_pixel);

    if (kill_timeout_seconds > 0)
    {
        if (thread_pool.kill_at_timeout(kill_timeout_seconds))
        {
            cg_assert(!bool("Process ran into timeout - is there an infinite "
                            "loop?"));
        }
    }
    else
    {
        thread_pool.wait();
    }
    thread_pool.poll_exceptions();
    timer.stop();
    std::cout << "Rendering time: " << timer.getElapsedTimeInMilliSec() << "ms" << std::endl;
    frame_buffer.saveTGA(context.params.output_file_name.c_str(), 2.2f);

    return 0;
}
Exemplo n.º 3
0
int
run_main (int, ACE_TCHAR *[])
{
  ACE_START_TEST (ACE_TEXT ("Thread_Pool_Test"));

#if defined (ACE_HAS_THREADS)
  int n_threads = ACE_MAX_THREADS;

  // Create the worker tasks.
  Thread_Pool thread_pool (n_threads);

  ACE_DEBUG ((LM_DEBUG,
              ACE_TEXT ("(%t) running test with %d threads\n"),
              n_threads));

  ACE_DEBUG ((LM_DEBUG,
              ACE_TEXT ("(%t) starting empty message shutdown test\n")));

  // Activate the task's thread pool, produce the messages that are,
  // produce the messages that are consumed by the threads in the
  // thread pool, and demonstrate how to shutdown by enqueueing
  // "empty" messages into the queue.
  if (thread_pool.test_empty_message_shutdown () == -1)
    return 1;

  ACE_DEBUG ((LM_DEBUG,
              ACE_TEXT ("(%t) waiting for worker tasks to finish...\n")));
  // Wait for all the threads to reach their exit point, at which
  // point the barrier in the destructor of the <ACE_Task> portion of
  // <Thread_Pool> will return.
  if (thread_pool.wait () == -1)
    return 1;

  ACE_DEBUG ((LM_DEBUG,
              ACE_TEXT ("(%t) starting queue deactivation shutdown test\n")));

  // Activate the task's thread pool, produce the messages that are
  // consumed by the threads in the thread pool, and demonstate how to
  // shutdown using the <ACE_Message_Queue::deactivate> method.
  if (thread_pool.test_queue_deactivation_shutdown () == -1)
    return 1;

  ACE_DEBUG ((LM_DEBUG,
              ACE_TEXT ("(%t) waiting for worker tasks to finish...\n")));
  // Wait for all the threads to reach their exit point, at which
  // point the barrier in the destructor of the <ACE_Task> portion of
  // <Thread_Pool> will return.
  if (thread_pool.wait () == -1)
    return 1;

  ACE_DEBUG ((LM_DEBUG,
              ACE_TEXT ("(%t) all worker tasks destroyed, exiting test...\n")));
#else
  ACE_ERROR ((LM_INFO,
              ACE_TEXT ("threads not supported on this platform\n")));
#endif /* ACE_HAS_THREADS */
  ACE_END_TEST;
  return 0;
}
Exemplo n.º 4
0
int main(int argc, char** argv) {
    //const int loop_size = 1000000;
    const int loop_size = 100000;
    //const int thread_size = std::thread::hardware_concurrency();
    const int thread_size = 2;
    std::cout << "thread_size = " << thread_size << std::endl;

    MyTimer timer;
    benchmark<lock_based_queue>("lock_based_queue", timer, thread_size, loop_size);
    benchmark<lock_based_stack>("lock_based_stack", timer, thread_size, loop_size);
    benchmark<boost_lock_free_queue>("boost_lock_free_queue", timer, thread_size, loop_size);
    benchmark<boost_lock_free_stack>("boost_lock_free_stack", timer, thread_size, loop_size);

/*
    WorkerThreadGroup<lock_based_queue<std::shared_ptr<BenchMarkTask> > > bm_worker_lbspg(thread_size);
    timer.start("lock_based_queue<std::shared_ptr<BenchMarkTask> > group");
    for(int i=0; i<loop_size; ++i) {
        bm_worker_lbspg.submit(std::make_shared<BenchMarkTask>());
    }
    bm_worker_lbspg.join();
    timer.stop();
*/
/*
    WorkerThread<lock_free_queue, BenchMarkJobPolicy> bm_worker_lf;
    timer.start("lock_free_queue<BenchMarkTask>");
    for(int i=0; i<loop_size; ++i) {
        bm_worker_lf.post(BenchMarkJob());
    }
    bm_worker_lf.join();
    timer.stop();
    std::cout << "total_counter: " << BenchMarkResource::total_counter << std::endl;
*/
/*
    WorkerThreadGroup<lock_free_queue, BenchMarkJobPolicy> bm_worker_lfg(thread_size);
    timer.start("lock_free_queue<BenchMarkTask>");
    for(int i=0; i<loop_size; ++i) {
        bm_worker_lfg.post(BenchMarkJob());
    }
    bm_worker_lfg.join();
    timer.stop();
    std::cout << "total_counter: " << BenchMarkResource::total_counter << std::endl;
*/


    AsioThreadPool<BenchmarkInitPolicy, BenchmarkEndPolicy> thread_pool(thread_size);

    timer.start("AsioThreadPool");
    for(int i=0; i<loop_size; ++i) {
        thread_pool.post(BenchmarkTask());
    }
    thread_pool.join();
    timer.stop();
    std::cout << "total_counter: " << total_counter << std::endl;
    //std::cout << "result.value(): " << result.value() << std::endl;


    timer.showResults();
}
Exemplo n.º 5
0
int main(int argc, char * argv[]) {
    utils::thread_pool thread_pool(2); 
    async_hello_world handler;
    std::string port = "8000";
    if (argc > 1) port = argv[1];
    server instance("localhost", port, handler, thread_pool, http::_reuse_address=true);
    instance.run();
    return 0;
}
int
run_main (int, ACE_TCHAR *[])
{
  ACE_START_TEST (ACE_TEXT ("Thread_Creation_Threshold_Test"));

#if defined (ACE_HAS_THREADS)
  ACE_DEBUG ((LM_DEBUG,
              ACE_TEXT ("(%P|%t) will try to start and kill up")
              ACE_TEXT (" to %u threads sequentially\n"),
              MAX_THREAD));
  int initial_pool_size = 50;

  // Create the worker tasks.
  Thread_Pool thread_pool (initial_pool_size);

  while (!thread_pool && thread_pool.total_threads() < MAX_THREAD)
    {
      // Activate the task's thread pool, produce the messages that are,
      // produce the messages that are consumed by the threads in the
      // thread pool, and demonstrate how to shutdown by enqueueing
      // "empty" messages into the queue.
      thread_pool.start ();

      // Wait for all the threads to reach their exit point, at which
      // point the barrier in the destructor of the <ACE_Task> portion of
      // <Thread_Pool> will return.
      if (thread_pool.wait () == -1)
        {
          ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("wait")), 1);
        }

      if (PRINT_DEBUG_MSGS)
        ACE_DEBUG ((LM_DEBUG,
                    ACE_TEXT ("%u total threads\n"),
                    thread_pool.total_threads()));

      int& n_threads = thread_pool.n_threads_;
      const unsigned long THREAD_THRESHOLD = 63336;
      if (thread_pool.total_threads() >= (THREAD_THRESHOLD - n_threads))
        n_threads = 1;
    }

  ACE_DEBUG ((LM_DEBUG,
              ACE_TEXT ("%u total threads successfully started and died;")
              ACE_TEXT (" expected %u.\n"),
              thread_pool.total_threads (),
              MAX_THREAD));
#else
  ACE_ERROR ((LM_INFO,
              ACE_TEXT ("threads not supported on this platform\n")));
#endif /* ACE_HAS_THREADS */
  ACE_END_TEST;
  return 0;
}
Exemplo n.º 7
0
void do_work(int num_of_threads, int num_of_values) {
	try {
		// Thread pool will start automatically and stop upon exit.
		ThreadPool thread_pool(num_of_threads);
		for (int i = 0; i < num_of_values; i++) {
			thread_pool.submit(std::make_shared<MyTask>(i));
		}
	}
	catch (const std::exception &e) {
		std::cerr << e.what() << std::endl;
	}
}
Exemplo n.º 8
0
int main(int argc, char* argv[]) {
  utils::thread_pool thread_pool(2);
  async_hello_world handler;
  std::string port = "8000";
  if (argc > 1)
    port = argv[1];
  http::server_options options;
  options.port(port).address("localhost").reuse_address(true);
  server instance(options, thread_pool, handler);
  instance.run();
  return 0;
}
Exemplo n.º 9
0
void file_manager::search(suffix_array_builder & sa_builder)
{
    thread_pool thread_pool(boost::thread::hardware_concurrency());
    boost::shared_future<void> root_dir_future = thread_pool.add_task(boost::bind(&file_manager::get_files_from_dir, this, root_dir_, boost::ref(thread_pool), boost::ref(sa_builder)));
    remaining_dirs_.push(root_dir_future);
    while(!remaining_dirs_.empty())
    {
        boost::shared_future<void> dir_future = remaining_dirs_.front();
        dir_future.wait();
        remaining_dirs_.pop();
    }
}
Exemplo n.º 10
0
int main(void) {
    Threadpool thread_pool(5,4);
    thread_pool.start();

    MyTask task;
    while (1) {
        thread_pool.addTask(task);
        sleep(1);
    }

    thread_pool.stop();

    return 0;
}
Exemplo n.º 11
0
void loadMetadata(Context & context)
{
	String path = context.getPath() + "metadata";

	/** There may exist 'force_restore_data' file, that means,
	  *  skip safety threshold on difference of data parts while initializing tables.
	  * This file is deleted after successful loading of tables.
	  * (flag is "one-shot")
	  */
	Poco::File force_restore_data_flag_file(context.getFlagsPath() + "force_restore_data");
	bool has_force_restore_data_flag = force_restore_data_flag_file.exists();

	/// For parallel tables loading.
	ThreadPool thread_pool(SettingMaxThreads().getAutoValue());

	/// Loop over databases.
	Poco::DirectoryIterator dir_end;
	for (Poco::DirectoryIterator it(path); it != dir_end; ++it)
	{
		if (!it->isDirectory())
			continue;

		/// For '.svn', '.gitignore' directory and similar.
		if (it.name().at(0) == '.')
			continue;

		String database = unescapeForFileName(it.name());

		/// There may exist .sql file with database creation statement.
		/// Or, if it is absent, then database with default engine is created.

		String database_attach_query;
		String database_metadata_file = it->path() + ".sql";

		if (Poco::File(database_metadata_file).exists())
		{
			ReadBufferFromFile in(database_metadata_file, 1024);
			readStringUntilEOF(database_attach_query, in);
		}
		else
			database_attach_query = "ATTACH DATABASE " + backQuoteIfNeed(database);

		executeCreateQuery(database_attach_query, context, database, it->path(), thread_pool, has_force_restore_data_flag);
	}

	thread_pool.wait();

	if (has_force_restore_data_flag)
		force_restore_data_flag_file.remove();
}
Exemplo n.º 12
0
void loadMetadata(Context & context)
{
	String path = context.getPath() + "metadata";

	/// Используется для параллельной загрузки таблиц.
	ThreadPool thread_pool(SettingMaxThreads().getAutoValue());

	/// Цикл по базам данных
	Poco::DirectoryIterator dir_end;
	for (Poco::DirectoryIterator it(path); it != dir_end; ++it)
	{
		if (!it->isDirectory())
			continue;

		/// Для директории .svn
		if (it.name().at(0) == '.')
			continue;

		String database = unescapeForFileName(it.name());

		/// Для базы данных может быть расположен .sql файл, где описан запрос на её создание.
		/// А если такого файла нет, то создаётся база данных с движком по-умолчанию.

		String database_attach_query;
		String database_metadata_file = it->path() + ".sql";

		if (Poco::File(database_metadata_file).exists())
		{
			ReadBufferFromFile in(database_metadata_file, 1024);
			readStringUntilEOF(database_attach_query, in);
		}
		else
			database_attach_query = "ATTACH DATABASE " + backQuoteIfNeed(database);

		executeCreateQuery(database_attach_query, context, database, it->path(), thread_pool);
	}

	thread_pool.wait();
}
Exemplo n.º 13
0
void update() {
  if (object_vec.size() > 0) {
    if (ballCol) {
      vec<vec<int> > cont;

      if (use_quadtree) {
        quadtree.update();
        quadtree.get(cont);
      } else if (use_fixedgrid) {
        fixedgrid.update();
        fixedgrid.get(cont);
      }

      // If we´re using collision optimizations
      if (use_quadtree || use_fixedgrid)
        Calc(cont, 0, cont.size());
      else if (numThreads > 0) {
        // Multithreading. DOESNT WORK.
        int total = object_vec.size();
        int parts = total / numThreads;

        std::vector<std::thread> thread_pool(numThreads);

        process_segment(parts * numThreads, total);

        for (int i = 0; i < numThreads; ++i) {
          thread_pool[i] =
              std::thread(process_segment, parts * i, parts * (i + 1));
        }
        for (auto &thread : thread_pool) thread.join();
      } else
        process_segment(0, object_vec.size());
    }

    // Update each objects position
    for (auto &object : object_vec) object->update();
  }
}
Exemplo n.º 14
0
int main(int argc, char* argv[])
{
    std::string config_filename;
    std::vector<std::string> args(argv, argv+argc);

    if (args.size() == 3)
    {
        if (args[1] == "-c")
        {
            config_filename = args[2];
        }
        else
        {
            printf("Usage: %s -c conf.xml \n", argv[0]);
            return 1;
        }
    }
    else
    {
        printf("Usage: %s -c conf.xml \n", argv[0]);
        return 1;
    }

    BLITZ_LOG_INFO("Starting blitz daemon");

    try
    {
        blitz::Config conf;
        conf.readConfig(config_filename);

        blitz::IOServicePool thread_pool(conf.getNumThreads());

        blitz::Daemon::daemonize(conf.getPidfile().c_str(), conf.getLogfile().c_str());

        blitz::WebService web_service(thread_pool.getIOService(), conf.getWebServicePort());

        for (unsigned i = 0; i < conf.getNumPipeline(); i++)
        {
            boost::asio::io_service& io_service = thread_pool.getIOService();
            blitz::DataSource* source = new blitz::HttpSource(io_service, conf.getPipelineSourceURL(i));
            blitz::DataSink* sink = new blitz::HttpSink(io_service, conf.getPipelineSinkPort(i), conf.getPipelineSinkIP(i),
                                                        conf.getPipelineName(i), conf.getPipelineID(i));
            source->addSink(sink);
            source->start();
            blitz::Controler* controler = dynamic_cast<blitz::Controler*>(sink);
            web_service.registerControler(controler);
        }

        if (conf.isVodServiceEnable())
        {
            boost::asio::io_service& io_service = thread_pool.getIOService();
            blitz::VODService* vservice = new blitz::VODService(io_service, conf.getVodServicePort(), conf.getVodServiceIP(), conf.getVodServiceFilePath());
            blitz::Controler* vservice_controler = dynamic_cast<blitz::Controler*>(vservice);
            web_service.registerControler(vservice_controler);
            vservice->start();
        }

        web_service.start();

        thread_pool.run();
    }
    catch (std::exception& e)
    {
        // this is in log file
        BLITZ_LOG_ERROR("Exception: %s", e.what());
        exit(1);
    }

    return 0;
}
Exemplo n.º 15
0
TEST(BasicThreadPoolTest, StartPoolTest) {
  uint8_t buffer[512];
  ThreadPool thread_pool(2, buffer, sizeof(buffer));

  ASSERT_TRUE(thread_pool.Start());
}
Exemplo n.º 16
0
 // cause the thread pool to begin its destruction process when 
 // global objects start to be destroyed
 ~threader_destruct_helper()
 {
     thread_pool().destruct_if_ready();
 }
Exemplo n.º 17
0
  static gboolean
gegl_operation_composer3_process (GeglOperation        *operation,
    GeglOperationContext *context,
    const gchar          *output_prop,
    const GeglRectangle  *result,
    gint                  level)
{
  GeglOperationComposer3Class *klass   = GEGL_OPERATION_COMPOSER3_GET_CLASS (operation);
  GeglBuffer                  *input;
  GeglBuffer                  *aux;
  GeglBuffer                  *aux2;
  GeglBuffer                  *output;
  gboolean                     success = FALSE;

  if (strcmp (output_prop, "output"))
  {
    g_warning ("requested processing of %s pad on a composer", output_prop);
    return FALSE;
  }

  if (result->width == 0 || result->height == 0)
  {
    output = gegl_operation_context_get_target (context, "output");
    return TRUE;
  }

  input = gegl_operation_context_get_source (context, "input");
  output = gegl_operation_context_get_output_maybe_in_place (operation,
                                                             context,
                                                             input,
                                                             result);

  aux   = gegl_operation_context_get_source (context, "aux");
  aux2  = gegl_operation_context_get_source (context, "aux2");

  /* A composer with a NULL aux, can still be valid, the
   * subclass has to handle it.
   */
  if (input != NULL ||
      aux != NULL ||
      aux2 != NULL)
    {
      if (gegl_operation_use_threading (operation, result))
      {
        gint threads = gegl_config_threads ();
        GThreadPool *pool = thread_pool ();
        ThreadData thread_data[GEGL_MAX_THREADS];
        gint pending = threads;

        if (result->width > result->height)
        {
          gint bit = result->width / threads;
          for (gint j = 0; j < threads; j++)
          {
            thread_data[j].roi.y = result->y;
            thread_data[j].roi.height = result->height;
            thread_data[j].roi.x = result->x + bit * j;
            thread_data[j].roi.width = bit;
          }
          thread_data[threads-1].roi.width = result->width - (bit * (threads-1));
        }
        else
        {
          gint bit = result->height / threads;
          for (gint j = 0; j < threads; j++)
          {
            thread_data[j].roi.x = result->x;
            thread_data[j].roi.width = result->width;
            thread_data[j].roi.y = result->y + bit * j;
            thread_data[j].roi.height = bit;
          }
          thread_data[threads-1].roi.height = result->height - (bit * (threads-1));
        }
        for (gint i = 0; i < threads; i++)
        {
          thread_data[i].klass = klass;
          thread_data[i].operation = operation;
          thread_data[i].input = input;
          thread_data[i].aux = aux;
          thread_data[i].aux2 = aux2;
          thread_data[i].output = output;
          thread_data[i].pending = &pending;
          thread_data[i].level = level;
          thread_data[i].success = TRUE;
        }

        for (gint i = 1; i < threads; i++)
          g_thread_pool_push (pool, &thread_data[i], NULL);
        thread_process (&thread_data[0], NULL);

        while (g_atomic_int_get (&pending)) {};
        
        success = thread_data[0].success;
      }
      else
      {
        success = klass->process (operation, input, aux, aux2, output, result, level);
      }

      g_clear_object (&input);
      g_clear_object (&aux);
      g_clear_object (&aux2);
    }
  else
    {
      g_warning ("%s received NULL input, aux, and aux2",
                 gegl_node_get_operation (operation->node));
    }

  return success;
}
Exemplo n.º 18
0
int HostRender::run_interactive(RaytracingContext& context, PixelFuncRaw const& render_pixel,
                                std::function<void()> const& render_overlay)
{
    Image      frame_buffer(context.params.image_width, context.params.image_height);
    ThreadPool thread_pool(context.params.num_threads);
    std::vector<glm::ivec2> tile_idx;

    if (!GUI::init_host(context.params))
    {
        return 1;
    }

    if(context.scene)
        context.scene->set_active_camera();

    // Launch first render.
    launch(&frame_buffer, thread_pool, &context, &tile_idx, render_pixel);

    auto time_last_frame = std::chrono::high_resolution_clock::now();

    RaytracingParameters oldParams = context.params;
    while (GUI::keep_running())
    {
        GUI::poll_events();
        thread_pool.poll_exceptions();

        // Restart rendering if parameters have changed.
        auto cam = Camera::get_active();
        if ((cam && cam->requires_restart())
                || context.params.change_requires_restart(oldParams))
        {
            thread_pool.terminate();
            if (oldParams.scene != context.params.scene) {
                // reload scene
                switch (context.params.scene) {
                case RaytracingParameters::CORNELL_BOX:
                    context.scene = context.scenes["cornell_box"];
                    break;
                case RaytracingParameters::SPHERE_PORTRAIT:
                    context.scene = context.scenes["sphere_portrait"];
                    break;
                default:
                    cg_assert(!"should not happen");
                }
                cg_assert(context.scene);
                context.scene->set_active_camera();
            }
            context.scene->refresh_scene(context.params);
            oldParams = context.params;
            launch(&frame_buffer, thread_pool, &context, &tile_idx, render_pixel);
        }

        // Update the texture displayed online in regular intervals so that
        // we don't waste many cycles uploading all the time.
        auto const now = std::chrono::high_resolution_clock::now();
        float const mspf = 1000.f / static_cast<float>(context.params.fps);
        if (std::chrono::duration_cast<std::chrono::milliseconds>(now-time_last_frame).count() > mspf)
        {
            GUI::display_host(frame_buffer, render_overlay);
        }
    }

    GUI::cleanup();

    return 0;
}
Exemplo n.º 19
0
static gboolean
gegl_operation_filter_process (GeglOperation        *operation,
                               GeglOperationContext *context,
                               const gchar          *output_prop,
                               const GeglRectangle  *result,
                               gint                  level)
{
  GeglOperationFilterClass *klass;
  GeglBuffer               *input;
  GeglBuffer               *output;
  gboolean                  success = FALSE;

  klass = GEGL_OPERATION_FILTER_GET_CLASS (operation);

  g_assert (klass->process);

  if (strcmp (output_prop, "output"))
    {
      g_warning ("requested processing of %s pad on a filter", output_prop);
      return FALSE;
    }

  input  = (GeglBuffer*)gegl_operation_context_dup_object (context, "input");
  output = gegl_operation_context_get_output_maybe_in_place (operation,
                                                             context,
                                                             input,
                                                             result);

  if (gegl_operation_use_threading (operation, result))
  {
    gint threads = gegl_config_threads ();
    GeglSplitStrategy split_strategy = GEGL_SPLIT_STRATEGY_AUTO;
    GThreadPool *pool = thread_pool ();
    ThreadData thread_data[GEGL_MAX_THREADS];
    gint pending = threads;

    if (klass->get_split_strategy)
    {
      split_strategy = klass->get_split_strategy (operation, context,
                                                  output_prop, result, level);
    }

    if (split_strategy == GEGL_SPLIT_STRATEGY_AUTO)
    {
      if (result->width > result->height)
        split_strategy = GEGL_SPLIT_STRATEGY_VERTICAL;
      else
        split_strategy = GEGL_SPLIT_STRATEGY_HORIZONTAL;
    }

    if (split_strategy == GEGL_SPLIT_STRATEGY_VERTICAL)
    {
      gint bit = result->width / threads;
      for (gint j = 0; j < threads; j++)
      {
        thread_data[j].roi.y = result->y;
        thread_data[j].roi.height = result->height;
        thread_data[j].roi.x = result->x + bit * j;
        thread_data[j].roi.width = bit;
      }
      thread_data[threads-1].roi.width = result->width - (bit * (threads-1));
    }
    else if (split_strategy == GEGL_SPLIT_STRATEGY_HORIZONTAL)
    {
      gint bit = result->height / threads;
      for (gint j = 0; j < threads; j++)
      {
        thread_data[j].roi.x = result->x;
        thread_data[j].roi.width = result->width;
        thread_data[j].roi.y = result->y + bit * j;
        thread_data[j].roi.height = bit;
      }
      thread_data[threads-1].roi.height = result->height - (bit * (threads-1));
    }
    else
    {
      g_return_val_if_reached (FALSE);
    }
    for (gint i = 0; i < threads; i++)
    {
      thread_data[i].klass = klass;
      thread_data[i].operation = operation;
      thread_data[i].context = context;
      thread_data[i].output = output;
      thread_data[i].pending = &pending;
      thread_data[i].level = level;
      thread_data[i].success = TRUE;
    }

    for (gint i = 1; i < threads; i++)
      g_thread_pool_push (pool, &thread_data[i], NULL);
    thread_process (&thread_data[0], g_object_ref (input));

    while (g_atomic_int_get (&pending)) {};

    success = thread_data[0].success;
  }
  else
  {
    success = klass->process (operation, input, output, result, level);
  }

  g_clear_object (&input);
  return success;
}