1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2020 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the documentation of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:FDL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Free Documentation License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Free |
19 | ** Documentation License version 1.3 as published by the Free Software |
20 | ** Foundation and appearing in the file included in the packaging of |
21 | ** this file. Please review the following information to ensure |
22 | ** the GNU Free Documentation License version 1.3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. |
24 | ** $QT_END_LICENSE$ |
25 | ** |
26 | ****************************************************************************/ |
27 | |
28 | /*! |
29 | \page qtconcurrenttask.html |
30 | \title Concurrent Task |
31 | \ingroup thread |
32 | |
33 | QtConcurrent::task provides an alternative interface for running a |
34 | task in a separate thread. The return value of the function is made |
35 | available through the QFuture API. |
36 | |
37 | If you want to just run a function in a separate thread without adjusting |
38 | any parameters, use QtConcurrent::run as that lets you write less code. |
39 | The QtConcurrent::task is designed for cases where you need to perform |
40 | extra configurations steps. |
41 | |
42 | This function is a part of the \l {Qt Concurrent} framework. |
43 | |
44 | \section1 Fluent interface |
45 | |
46 | The QtConcurrent::task returns an instance of an auxiliary class called |
47 | QtConcurrent::QTaskBuilder. Normally, you don't need to create an instance |
48 | of this class manually. The QtConcurrent::QTaskBuilder provides an interface |
49 | to adjust different task parameters in a chain-like manner. This approach |
50 | is known as a |
51 | \l {https://en.wikipedia.org/wiki/Fluent_interface}{fluent interface}. |
52 | |
53 | You can just set the parameters you need and then kick a task off. |
54 | In order to finalize the configuration of a task you must invoke |
55 | QtConcurrent::QTaskBuilder::spawn. This function is non-blocking (i.e. |
56 | returns a future object immediately), but it's not guaranteed that the |
57 | task starts immediately. You can use the QFuture and QFutureWatcher classes |
58 | to monitor the status of the task. |
59 | |
60 | See more examples and explanations below. |
61 | |
62 | \section1 Running a task in a separate thread |
63 | |
64 | To run a function in another thread, use QtConcurrent::QTaskBuilder::spawn: |
65 | |
66 | \snippet code/src_concurrent_qtconcurrenttask.cpp 0 |
67 | |
68 | This will run a lambda function in a separate thread obtained from |
69 | the default QThreadPool. |
70 | |
71 | \section1 Passing arguments to the task |
72 | |
73 | Invoking a function with arguments is done by passing them to |
74 | QtConcurrent::QTaskBuilder::withArguments: |
75 | |
76 | \snippet code/src_concurrent_qtconcurrenttask.cpp 1 |
77 | |
78 | A copy of each argument is made at the point where |
79 | QtConcurrent::QTaskBuilder::withArguments is called, and these values |
80 | are passed to the thread when it begins executing the task. Changes made |
81 | to the arguments after calling QtConcurrent::QTaskBuilder::withArguments |
82 | are not visible to the thread. |
83 | |
84 | If you want to run a function that accepts arguments by reference, you |
85 | should use \l {https://en.cppreference.com/w/cpp/utility/functional/ref} |
86 | {std::ref/cref} auxiliary functions. These functions create thin wrappers |
87 | around passed arguments: |
88 | |
89 | \snippet code/src_concurrent_qtconcurrenttask.cpp 2 |
90 | |
91 | Make sure that all wrapped objects live long enough. It is possible to |
92 | get undefined behavior if a task outlives the object wrapped by |
93 | std::ref/cref. |
94 | |
95 | \section1 Returning values from the task |
96 | |
97 | You can obtain the result of a task with the QFuture API: |
98 | |
99 | \snippet code/src_concurrent_qtconcurrenttask.cpp 3 |
100 | |
101 | Note that QFuture::result() is a blocking call, it waits for the |
102 | result to become available. Use QFutureWatcher to get a notification |
103 | when the task has finished execution and the result is available. |
104 | |
105 | In case you want to pass a result to another asynchronous task, you can |
106 | use QFuture::then() to create a chain of dependent tasks. See the QFuture |
107 | documentation for more details. |
108 | |
109 | \section1 Additional API features |
110 | |
111 | \section2 Using different types of callable objects |
112 | |
113 | Strictly speaking, you can use any type of tasks and arguments that |
114 | satisfy the following condition: |
115 | |
116 | \snippet code/src_concurrent_qtconcurrenttask.cpp 4 |
117 | |
118 | You can use a free function: |
119 | |
120 | \snippet code/src_concurrent_qtconcurrenttask.cpp 5 |
121 | |
122 | You can use a member function: |
123 | |
124 | \snippet code/src_concurrent_qtconcurrenttask.cpp 6 |
125 | |
126 | You can use a callable object with an operator(): |
127 | |
128 | \snippet code/src_concurrent_qtconcurrenttask.cpp 7 |
129 | |
130 | If you want to use an existing callable object, you need to either |
131 | copy/move it to QtConcurrent::task or wrap it with std::ref/cref: |
132 | |
133 | \snippet code/src_concurrent_qtconcurrenttask.cpp 8 |
134 | |
135 | \section2 Using custom thread pool |
136 | |
137 | You can specify a custom thread pool: |
138 | |
139 | \snippet code/src_concurrent_qtconcurrenttask.cpp 9 |
140 | |
141 | \section2 Setting priority for a task |
142 | |
143 | You can set the priority for a task: |
144 | |
145 | \snippet code/src_concurrent_qtconcurrenttask.cpp 10 |
146 | |
147 | If you don't need a future object, you can call |
148 | QtConcurrent::QTaskBuilder::spawn(QtConcurrent::FutureResult::Ignore): |
149 | |
150 | \snippet code/src_concurrent_qtconcurrenttask.cpp 11 |
151 | |
152 | You can access the promise object associated with the task by defining an |
153 | additional argument of \c {QPromise<T> &} type inside the function. |
154 | This additional argument must be the first argument passed to the function, and |
155 | like in \l {Concurrent Run With Promise} mode, the function is expected to return void type. |
156 | Result reporting is done through QPromise API: |
157 | |
158 | \snippet code/src_concurrent_qtconcurrenttask.cpp 12 |
159 | */ |
160 | |
161 | /*! |
162 | \fn template <typename Task> [[nodiscard]] QTaskBuilder<Task> QtConcurrent::task(Task &&task); |
163 | \since 6.0 |
164 | |
165 | Creates an instance of QtConcurrent::QTaskBuilder. This object can be used |
166 | to adjust some parameters and run \a task in a separate thread. |
167 | |
168 | \sa {Concurrent Task}, QtConcurrent::QTaskBuilder |
169 | */ |
170 | |