summaryrefslogtreecommitdiffstats
path: root/src/concurrent/qtconcurrenttask.qdoc
blob: 6f21ac13959a161215190e6794e3f473efa737f5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// 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
    \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 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
*/