/**
 * g_thread_pool_free:
 * @pool: a #GThreadPool
 * @immediate: should @pool shut down immediately?
 * @wait_: should the function wait for all tasks to be finished?
 *
 * Frees all resources allocated for @pool.
 *
 * If @immediate is %TRUE, no new task is processed for
 * @pool. Otherwise @pool is not freed before the last task is
 * processed. Note however, that no thread of this pool is
 * interrupted, while processing a task. Instead at least all still
 * running threads can finish their tasks before the @pool is freed.
 *
 * If @wait_ is %TRUE, the functions does not return before all tasks
 * to be processed (dependent on @immediate, whether all or only the
 * currently running) are ready. Otherwise the function returns immediately.
 *
 * After calling this function @pool must not be used anymore. 
 **/
void
g_thread_pool_free (GThreadPool *pool,
		    gboolean     immediate,
		    gboolean     wait_)
{
  GRealThreadPool *real;

  real = (GRealThreadPool*) pool;

  g_return_if_fail (real);
  g_return_if_fail (real->running);

  /* If there's no thread allowed here, there is not much sense in
   * not stopping this pool immediately, when it's not empty 
   */
  g_return_if_fail (immediate || 
		    real->max_threads != 0 || 
		    g_async_queue_length (real->queue) == 0);

  g_async_queue_lock (real->queue);

  real->running = FALSE;
  real->immediate = immediate;
  real->waiting = wait_;

  if (wait_)
    {
      real->cond = g_cond_new ();

      while (g_async_queue_length_unlocked (real->queue) != -real->num_threads &&
	     !(immediate && real->num_threads == 0))
	g_cond_wait (real->cond, _g_async_queue_get_mutex (real->queue));
    }

  if (immediate || g_async_queue_length_unlocked (real->queue) == -real->num_threads)
    {
      /* No thread is currently doing something (and nothing is left
       * to process in the queue) 
       */
      if (real->num_threads == 0) 
	{
	  /* No threads left, we clean up */
	  g_async_queue_unlock (real->queue);
	  g_thread_pool_free_internal (real);
	  return;
	}

      g_thread_pool_wakeup_and_stop_all (real);
    }
  
  /* The last thread should cleanup the pool */
  real->waiting = FALSE; 
  g_async_queue_unlock (real->queue);
}
Ejemplo n.º 2
0
static gpointer
g_thread_pool_thread_proxy (gpointer data)
{
  GRealThreadPool *pool;

  pool = data;

  DEBUG_MSG (("thread %p started for pool %p.", g_thread_self (), pool));

  g_async_queue_lock (pool->queue);

  while (TRUE)
    {
      gpointer task;

      task = g_thread_pool_wait_for_new_task (pool);
      if (task)
        {
          if (pool->running || !pool->immediate)
            {
              /* A task was received and the thread pool is active,
               * so execute the function.
               */
              g_async_queue_unlock (pool->queue);
              DEBUG_MSG (("thread %p in pool %p calling func.",
                          g_thread_self (), pool));
              pool->pool.func (task, pool->pool.user_data);
              g_async_queue_lock (pool->queue);
            }
        }
      else
        {
          /* No task was received, so this thread goes to the global pool. */
          gboolean free_pool = FALSE;

          DEBUG_MSG (("thread %p leaving pool %p for global pool.",
                      g_thread_self (), pool));
          pool->num_threads--;

          if (!pool->running)
            {
              if (!pool->waiting)
                {
                  if (pool->num_threads == 0)
                    {
                      /* If the pool is not running and no other
                       * thread is waiting for this thread pool to
                       * finish and this is the last thread of this
                       * pool, free the pool.
                       */
                      free_pool = TRUE;
                    }
                  else
                    {
                      /* If the pool is not running and no other
                       * thread is waiting for this thread pool to
                       * finish and this is not the last thread of
                       * this pool and there are no tasks left in the
                       * queue, wakeup the remaining threads.
                       */
                      if (g_async_queue_length_unlocked (pool->queue) ==
                          - pool->num_threads)
                        g_thread_pool_wakeup_and_stop_all (pool);
                    }
                }
              else if (pool->immediate ||
                       g_async_queue_length_unlocked (pool->queue) <= 0)
                {
                  /* If the pool is not running and another thread is
                   * waiting for this thread pool to finish and there
                   * are either no tasks left or the pool shall stop
                   * immediately, inform the waiting thread of a change
                   * of the thread pool state.
                   */
                  g_cond_broadcast (&pool->cond);
                }
            }

          g_async_queue_unlock (pool->queue);

          if (free_pool)
            g_thread_pool_free_internal (pool);

          if ((pool = g_thread_pool_wait_for_new_pool ()) == NULL)
            break;

          g_async_queue_lock (pool->queue);

          DEBUG_MSG (("thread %p entering pool %p from global pool.",
                      g_thread_self (), pool));

          /* pool->num_threads++ is not done here, but in
           * g_thread_pool_start_thread to make the new started
           * thread known to the pool before itself can do it.
           */
        }
    }

  return NULL;
}