Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2015-11-02 18:57:48 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2015-11-02 18:57:48 +0300
commit04ac8768efc342997f941f08688398c1d90bec79 (patch)
tree920b490353401e322385cbc38b8a7022da2e0cae /source
parent44774f81606f74b0268f7e6fa58e67f1f8c28ca7 (diff)
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
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenlib/BLI_task.h1
-rw-r--r--source/blender/blenlib/intern/task.c56
2 files changed, 56 insertions, 1 deletions
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 3bf58a64307..81c277cd956 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 20ea5ec5ec8..3374a589fc3 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);