/** * 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); }
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; }