Revision control
++ // Copyright (C) 2020 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
++
++ /*!
++ \page qtconcurrenttask.html
++ \title Concurrent Task
++ \brief A configurable way to run a task in a separate thread.
++ \ingroup thread
++
++ QtConcurrent::task provides an alternative interface for running a
++ task in a separate thread. The return value of the function is made
++ available through the QFuture API.
++
++ If you want to just run a function in a separate thread without adjusting
++ any parameters, use QtConcurrent::run as that lets you write less code.
++ The QtConcurrent::task is designed for cases where you need to perform
++ extra configurations steps.
++
++ This function is a part of the \l {Qt Concurrent} framework.
++
++ \section1 Optimize includes
++
++ If you include the \c <QtConcurrent> header, the entire Qt Concurrent
++ module with the entire Qt Core module will be included, which may increase
++ compilation times and binary sizes. To use the
++ \l {QtConcurrent::task}{QtConcurrent::task()} function, you can include a
++ more specific header:
++
++ \code
++ #include <QtConcurrentTask>
++ \endcode
++
++ \section1 Fluent interface
++
++ The QtConcurrent::task returns an instance of an auxiliary class called
++ QtConcurrent::QTaskBuilder. Normally, you don't need to create an instance
++ of this class manually. The QtConcurrent::QTaskBuilder provides an interface
++ to adjust different task parameters in a chain-like manner. This approach
++ is known as a
++ \l {https://en.wikipedia.org/wiki/Fluent_interface}{fluent interface}.
++
++ You can just set the parameters you need and then kick a task off.
++ In order to finalize the configuration of a task you must invoke
++ QtConcurrent::QTaskBuilder::spawn. This function is non-blocking (i.e.
++ returns a future object immediately), but it's not guaranteed that the
++ task starts immediately. You can use the QFuture and QFutureWatcher classes
++ to monitor the status of the task.
++
++ See more examples and explanations below.
++
++ \section1 Running a task in a separate thread
++
++ To run a function in another thread, use QtConcurrent::QTaskBuilder::spawn:
++
++ \snippet code/src_concurrent_qtconcurrenttask.cpp 0
++
++ This will run a lambda function in a separate thread obtained from
++ the default QThreadPool.
++
++ \section1 Passing arguments to the task
++
++ Invoking a function with arguments is done by passing them to
++ QtConcurrent::QTaskBuilder::withArguments:
++
++ \snippet code/src_concurrent_qtconcurrenttask.cpp 1
++
++ A copy of each argument is made at the point where
++ QtConcurrent::QTaskBuilder::withArguments is called, and these values
++ are passed to the thread when it begins executing the task. Changes made
++ to the arguments after calling QtConcurrent::QTaskBuilder::withArguments
++ are not visible to the thread.
++
++ If you want to run a function that accepts arguments by reference, you
++ should use \l {https://en.cppreference.com/w/cpp/utility/functional/ref}
++ {std::ref/cref} auxiliary functions. These functions create thin wrappers
++ around passed arguments:
++
++ \snippet code/src_concurrent_qtconcurrenttask.cpp 2
++
++ Make sure that all wrapped objects live long enough. It is possible to
++ get undefined behavior if a task outlives the object wrapped by
++ std::ref/cref.
++
++ \section1 Returning values from the task
++
++ You can obtain the result of a task with the QFuture API:
++
++ \snippet code/src_concurrent_qtconcurrenttask.cpp 3
++
++ Note that QFuture::result() is a blocking call, it waits for the
++ result to become available. Use QFutureWatcher to get a notification
++ when the task has finished execution and the result is available.
++
++ In case you want to pass a result to another asynchronous task, you can
++ use QFuture::then() to create a chain of dependent tasks. See the QFuture
++ documentation for more details.
++
++ \section1 Additional API features
++
++ \section2 Using different types of callable objects
++
++ Strictly speaking, you can use any type of tasks and arguments that
++ satisfy the following condition:
++
++ \snippet code/src_concurrent_qtconcurrenttask.cpp 4
++
++ You can use a free function:
++
++ \snippet code/src_concurrent_qtconcurrenttask.cpp 5
++
++ You can use a member function:
++
++ \snippet code/src_concurrent_qtconcurrenttask.cpp 6
++
++ You can use a callable object with an operator():
++
++ \snippet code/src_concurrent_qtconcurrenttask.cpp 7
++
++ If you want to use an existing callable object, you need to either
++ copy/move it to QtConcurrent::task or wrap it with std::ref/cref:
++
++ \snippet code/src_concurrent_qtconcurrenttask.cpp 8
++
++ \section2 Using custom thread pool
++
++ You can specify a custom thread pool:
++
++ \snippet code/src_concurrent_qtconcurrenttask.cpp 9
++
++ \section2 Setting priority for a task
++
++ You can set the priority for a task:
++
++ \snippet code/src_concurrent_qtconcurrenttask.cpp 10
++
++ If you don't need a future object, you can call
++ QtConcurrent::QTaskBuilder::spawn(QtConcurrent::FutureResult::Ignore):
++
++ \snippet code/src_concurrent_qtconcurrenttask.cpp 11
++
++ You can access the promise object associated with the task by defining an
++ additional argument of \c {QPromise<T> &} type inside the function.
++ This additional argument must be the first argument passed to the function, and
++ like in \l {Concurrent Run With Promise} mode, the function is expected to return void type.
++ Result reporting is done through QPromise API:
++
++ \snippet code/src_concurrent_qtconcurrenttask.cpp 12
++ */
++
++ /*!
++ \fn template <typename Task> [[nodiscard]] QTaskBuilder<Task> QtConcurrent::task(Task &&task);
++ \since 6.0
++
++ Creates an instance of QtConcurrent::QTaskBuilder. This object can be used
++ to adjust some parameters and run \a task in a separate thread.
++
++ \sa {Concurrent Task}, QtConcurrent::QTaskBuilder
++ */