Commit: 04ac8768efc342997f941f08688398c1d90bec79
Author: Bastien Montagne
Date:   Mon Nov 2 16:57:48 2015 +0100
Branches: master
https://developer.blender.org/rB04ac8768efc342997f941f08688398c1d90bec79

BLI_task: add support for full-background taskpools.

With current code, in single-threaded context, a pool of task may never be 
executed
until one calls BLI_task_pool_work_and_wait() on it, this is not acceptable for
asynchronous tasks where you never want to actually lock the main thread.

This commits adds an extra thread in single-threaded case, and a new 'type' of 
pool,
such that one can create real background pools of tasks. See code for details.

Review: D1565

===================================================================

M       source/blender/blenlib/BLI_task.h
M       source/blender/blenlib/intern/task.c

===================================================================

diff --git a/source/blender/blenlib/BLI_task.h 
b/source/blender/blenlib/BLI_task.h
index 3bf58a6..81c277c 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -77,6 +77,7 @@ typedef void (*TaskRunFunction)(TaskPool *__restrict pool, 
void *taskdata, int t
 typedef void (*TaskFreeFunction)(TaskPool *__restrict pool, void *taskdata, 
int threadid);
 
 TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata);
+TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler, void 
*userdata);
 void BLI_task_pool_free(TaskPool *pool);
 
 void BLI_task_pool_push_ex(
diff --git a/source/blender/blenlib/intern/task.c 
b/source/blender/blenlib/intern/task.c
index 20ea5ec..3374a58 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -61,12 +61,17 @@ struct TaskPool {
        ThreadMutex user_mutex;
 
        volatile bool do_cancel;
+
+       /* If set, this pool may never be work_and_wait'ed, which means 
TaskScheduler has to use its special
+        * background fallback thread in case we are in single-threaded 
situation. */
+       bool run_in_background;
 };
 
 struct TaskScheduler {
        pthread_t *threads;
        struct TaskThread *task_threads;
        int num_threads;
+       bool background_thread_only;
 
        ListBase queue;
        ThreadMutex queue_mutex;
@@ -152,6 +157,11 @@ static bool task_scheduler_thread_wait_pop(TaskScheduler 
*scheduler, Task **task
                     current_task = current_task->next)
                {
                        TaskPool *pool = current_task->pool;
+
+                       if (scheduler->background_thread_only && 
!pool->run_in_background) {
+                               continue;
+                       }
+
                        if (pool->num_threads == 0 ||
                            pool->currently_running_tasks < pool->num_threads)
                        {
@@ -216,6 +226,12 @@ TaskScheduler *BLI_task_scheduler_create(int num_threads)
        /* main thread will also work, so we count it too */
        num_threads -= 1;
 
+       /* Add background-only thread if needed. */
+       if (num_threads == 0) {
+           scheduler->background_thread_only = true;
+           num_threads = 1;
+       }
+
        /* launch threads that will be waiting for work */
        if (num_threads > 0) {
                int i;
@@ -326,15 +342,28 @@ static void task_scheduler_clear(TaskScheduler 
*scheduler, TaskPool *pool)
 
 /* Task Pool */
 
-TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata)
+static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, void *userdata, 
const bool is_background)
 {
        TaskPool *pool = MEM_callocN(sizeof(TaskPool), "TaskPool");
 
+#ifndef NDEBUG
+       /* Assert we do not try to create a background pool from some parent 
task - those only work OK from main thread. */
+       if (is_background) {
+               const pthread_t thread_id = pthread_self();
+        int i = scheduler->num_threads;
+
+               while (i--) {
+                       BLI_assert(scheduler->threads[i] != thread_id);
+               }
+       }
+#endif
+
        pool->scheduler = scheduler;
        pool->num = 0;
        pool->num_threads = 0;
        pool->currently_running_tasks = 0;
        pool->do_cancel = false;
+       pool->run_in_background = is_background;
 
        BLI_mutex_init(&pool->num_mutex);
        BLI_condition_init(&pool->num_cond);
@@ -353,6 +382,31 @@ TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, 
void *userdata)
        return pool;
 }
 
+/**
+ * Create a normal task pool.
+ * This means that in single-threaded context, it will not be executed at all 
until you call
+ * \a BLI_task_pool_work_and_wait() on it.
+ */
+TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata)
+{
+       return task_pool_create_ex(scheduler, userdata, false);
+}
+
+/**
+ * Create a background task pool.
+ * In multi-threaded context, there is no differences with \a 
BLI_task_pool_create(), but in single-threaded case
+ * it is ensured to have at least one worker thread to run on (i.e. you do not 
have to call
+ * \a BLI_task_pool_work_and_wait() on it to be sure it will be processed).
+ *
+ * \note Background pools are non-recursive (that is, you should not create 
other background pools in tasks assigned
+ *       to a brackground pool, they could end never being executed, since the 
'fallback' background thread is already
+ *       busy with parent task in single-threaded context).
+ */
+TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler, void 
*userdata)
+{
+       return task_pool_create_ex(scheduler, userdata, true);
+}
+
 void BLI_task_pool_free(TaskPool *pool)
 {
        BLI_task_pool_stop(pool);

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to