1e41f4b71Sopenharmony_ci# FFRT Development
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## When to Use
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ciFunction Flow is a task-based and data-driven concurrent programming model that allows you to develop an application by creating tasks and describing their dependencies. Function Flow Runtime (FFRT) is a software runtime library that works with the Function Flow programming model. It is used to schedule and execute tasks of an application developed on the Function Flow programming model. Specifically, FFRT automatically and concurrently schedules and executes tasks of the application based on the task dependency status and available resources, so that you can focus on feature development.
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciThis topic walks you through how to implement parallel programming based on the Function Flow programming model and FFRT.
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ci### Programming Models
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ci
12e41f4b71Sopenharmony_ci| Item | Thread Programming Model                                                | FFRT Programming Model                                            |
13e41f4b71Sopenharmony_ci| -------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
14e41f4b71Sopenharmony_ci| Degree of Parallelism (DOP) mining mode| Programmers create multiple threads and assign tasks to them for parallel execution to achieve the optimal runtime performance.| Programmers, with the help of compilers or programming language features, decompose the application into tasks and describe their data dependencies during static programming. The scheduler allocates tasks to worker threads for execution.|
15e41f4b71Sopenharmony_ci| Owner for creating threads| Programmers are responsible for creating threads. The maximum number of threads that can be created is not under control.| The scheduler is responsible for creating and managing worker threads. Programmers cannot directly create threads.|
16e41f4b71Sopenharmony_ci| Load balancing      | Programmers map tasks to threads during static programming. Improper mapping or uncertain task execution time will cause a load imbalance among threads.| A ready task is automatically scheduled to an idle thread for execution, reducing the load imbalance among threads.|
17e41f4b71Sopenharmony_ci| Scheduling overhead      | Thread scheduling is implemented by a kernel-mode scheduler, resulting in high scheduling overhead.                      | Thread scheduling is implemented by a user-mode coroutine scheduler, requiring less scheduling overhead. In addition, FFRT can further reduce the scheduling overhead through hardware-based scheduling offload.|
18e41f4b71Sopenharmony_ci| Dependency expression      | A thread is in the executable state once it is created, and it is executed parallelly with other threads, causing frequent thread switching.| FFRT determines whether a task can be executed based on the input and output dependencies explicitly expressed during task creation. If the input dependencies do not meet the requirements, the task is not scheduled.|
19e41f4b71Sopenharmony_ci
20e41f4b71Sopenharmony_ci## Basic Concepts
21e41f4b71Sopenharmony_ci
22e41f4b71Sopenharmony_ci### Function Flow
23e41f4b71Sopenharmony_ci
24e41f4b71Sopenharmony_ciThe Function Flow programming model allows you to develop an application by creating tasks and describing their dependencies. Its most outstanding features are task-based and data-driven.
25e41f4b71Sopenharmony_ci
26e41f4b71Sopenharmony_ci#### Task-based
27e41f4b71Sopenharmony_ci
28e41f4b71Sopenharmony_ciTask-based means that you can use tasks to express an application and schedule the tasks at runtime.
29e41f4b71Sopenharmony_ci
30e41f4b71Sopenharmony_ciA task is defined as a developer-oriented programming clue and a runtime-oriented execution object. It usually contains a set of sequential instructions and a data context environment to run the instructions.
31e41f4b71Sopenharmony_ci
32e41f4b71Sopenharmony_ciTasks in the Function Flow programming model have the following features:
33e41f4b71Sopenharmony_ci
34e41f4b71Sopenharmony_ci- The dependency between tasks can be specified in data-driven form.
35e41f4b71Sopenharmony_ci- Tasks can be nested. That is, when a task is being executed, a new task can be generated and delivered to that task to form a parent-child relationship.
36e41f4b71Sopenharmony_ci- Simultaneous operations, such as wait, lock, and condition variables, are supported.
37e41f4b71Sopenharmony_ci
38e41f4b71Sopenharmony_ci> **NOTE**
39e41f4b71Sopenharmony_ci>
40e41f4b71Sopenharmony_ci> The task granularity determines the number of concurrent tasks and therefore affects the application execution performance. A small granularity increases the scheduling overhead, whereas a large granularity decreases the DOP. The minimum task granularity allowed in the Function Flow programming model is 100 μs.
41e41f4b71Sopenharmony_ci
42e41f4b71Sopenharmony_ci#### Data-driven
43e41f4b71Sopenharmony_ci
44e41f4b71Sopenharmony_ciData-driven means that the dependency between tasks is expressed through data dependencies.
45e41f4b71Sopenharmony_ci
46e41f4b71Sopenharmony_ciData objects associated with a task are read and written during task execution. In the Function Flow programming model, a data object is abstracted as a data signature. They are in one-to-one mapping.
47e41f4b71Sopenharmony_ci
48e41f4b71Sopenharmony_ciData dependencies, consisting of **in_deps** and **out_deps**, are abstracted as a list of data signatures mapping to the data objects manipulated by the task. When the signature of a data object appears in **in_deps** of a task, the task is a consumer task of the data object. The execution of a consumer task does not change the content of the input data object. When the signature of a data object appears in **out_deps** of a task, the task is a producer task of the data object. The execution of a producer task changes the content of the output data object and generates a new version of the data object.
49e41f4b71Sopenharmony_ci
50e41f4b71Sopenharmony_ciA data object may have multiple versions. Each version corresponds to one producer task and zero, one, or more consumer tasks. A sequence of the data object versions and the version-specific producer task and consumer tasks are defined according to the delivery sequence of the producer task and consumer tasks.
51e41f4b71Sopenharmony_ci
52e41f4b71Sopenharmony_ciWhen all producer tasks and consumer tasks of the data object of all the available versions are executed, the data dependency is removed. In this case, the task enters the ready state and can be scheduled for execution.
53e41f4b71Sopenharmony_ci
54e41f4b71Sopenharmony_ciWith the data-driven dependency expression, FFRT can dynamically build different types of data dependencies between tasks and schedule the tasks based on the data dependency status at runtime. The following data dependency types are available:
55e41f4b71Sopenharmony_ci
56e41f4b71Sopenharmony_ci- Producer-Consumer dependency
57e41f4b71Sopenharmony_ci
58e41f4b71Sopenharmony_ci  A dependency formed between the producer task of a data object of a specific version and a consumer task of the data object of the same version. It is also referred to as a read-after-write dependency.
59e41f4b71Sopenharmony_ci
60e41f4b71Sopenharmony_ci- Consumer-Producer dependency
61e41f4b71Sopenharmony_ci
62e41f4b71Sopenharmony_ci  A dependency formed between a consumer task of a data object of a specific version and the producer task of the data object of the next version. It is also referred to as a write-after-read dependency.
63e41f4b71Sopenharmony_ci
64e41f4b71Sopenharmony_ci- Producer-Producer dependency
65e41f4b71Sopenharmony_ci
66e41f4b71Sopenharmony_ci  A dependency formed between the producer task of a data object of a specific version and a producer task of the data object of the next version. It is also referred to as a write-after-write dependency.
67e41f4b71Sopenharmony_ci
68e41f4b71Sopenharmony_ci
69e41f4b71Sopenharmony_ciAssume that the relationship between some tasks and data A is as follows:
70e41f4b71Sopenharmony_ci```{.c}
71e41f4b71Sopenharmony_citask1(OUT A);
72e41f4b71Sopenharmony_citask2(IN A);
73e41f4b71Sopenharmony_citask3(IN A);
74e41f4b71Sopenharmony_citask4(OUT A);
75e41f4b71Sopenharmony_citask5(OUT A);
76e41f4b71Sopenharmony_ci```
77e41f4b71Sopenharmony_ci
78e41f4b71Sopenharmony_ci<img src="figures/ffrtfigure3.png" style="zoom:40%" />
79e41f4b71Sopenharmony_ci
80e41f4b71Sopenharmony_ci> **NOTE**
81e41f4b71Sopenharmony_ci>
82e41f4b71Sopenharmony_ci> For ease of description, circles are used to represent tasks and squares are used to represent data.
83e41f4b71Sopenharmony_ci
84e41f4b71Sopenharmony_ciThe following conclusions can be drawn:
85e41f4b71Sopenharmony_ci- task1 and task2/task3 form a producer-consumer dependency. This means that task2/task3 can read data A only after task1 writes data A.
86e41f4b71Sopenharmony_ci- task2/task3 and task4 form a consumer-producer dependency. This means that task4 can write data A only after task2/task3 reads data A.
87e41f4b71Sopenharmony_ci- task 4 and task 5 form a producer-producer dependency. This means that task 5 can write data A only after task 4 writes data A.
88e41f4b71Sopenharmony_ci
89e41f4b71Sopenharmony_ci## Available APIs
90e41f4b71Sopenharmony_ci
91e41f4b71Sopenharmony_ci| API                                                      | Description                                                        |
92e41f4b71Sopenharmony_ci| ------------------------------------------------------------ | ------------------------------------------------------------ |
93e41f4b71Sopenharmony_ci| ffrt_condattr_init (ffrt_condattr_t* attr) | Initializes a condition variable attribute.|
94e41f4b71Sopenharmony_ci| ffrt_condattr_destroy(ffrt_condattr_t* attr)  | Destroys a condition variable attribute.|
95e41f4b71Sopenharmony_ci| ffrt_condattr_setclock(ffrt_condattr_t* attr, ffrt_clockid_t clock) | Sets the clock of a condition variable attribute.|
96e41f4b71Sopenharmony_ci| ffrt_condattr_getclock(const ffrt_condattr_t* attr, ffrt_clockid_t* clock)        | Obtains the clock of a condition variable attribute.             |
97e41f4b71Sopenharmony_ci| ffrt_cond_init(ffrt_cond_t* cond, const ffrt_condattr_t* attr)   | Initializes a condition variable.     |
98e41f4b71Sopenharmony_ci| ffrt_cond_signal(ffrt_cond_t* cond)         | Unblocks at least one of the threads that are blocked on a condition variable.|
99e41f4b71Sopenharmony_ci| ffrt_cond_broadcast(ffrt_cond_t* cond) | Unblocks all threads currently blocked on a condition variable.|
100e41f4b71Sopenharmony_ci| ffrt_cond_wait(ffrt_cond_t* cond, ffrt_mutex_t* mutex)            | Blocks the calling thread on a condition variable.|
101e41f4b71Sopenharmony_ci| ffrt_cond_timedwait(ffrt_cond_t* cond, ffrt_mutex_t* mutex, const struct timespec* time_point)            | Blocks the calling thread on a condition variable for a given duration.|
102e41f4b71Sopenharmony_ci| ffrt_cond_destroy(ffrt_cond_t* cond)            | Destroys a condition variable.|
103e41f4b71Sopenharmony_ci| ffrt_mutex_init(ffrt_mutex_t* mutex, const ffrt_mutexattr_t* attr) | Initializes a mutex.|
104e41f4b71Sopenharmony_ci| ffrt_mutex_lock(ffrt_mutex_t* mutex)   | Locks a mutex.|
105e41f4b71Sopenharmony_ci| ffrt_mutex_unlock(ffrt_mutex_t* mutex)  | Unlocks a mutex.|
106e41f4b71Sopenharmony_ci| ffrt_mutex_trylock(ffrt_mutex_t* mutex)   | Attempts to lock a mutex.|
107e41f4b71Sopenharmony_ci| ffrt_mutex_destroy(ffrt_mutex_t* mutex)   | Destroys a mutex.|
108e41f4b71Sopenharmony_ci| ffrt_queue_attr_init(ffrt_queue_attr_t* attr)    | Initializes a queue attribute.|
109e41f4b71Sopenharmony_ci| ffrt_queue_attr_destroy(ffrt_queue_attr_t* attr)    | Destroys a queue attribute.|
110e41f4b71Sopenharmony_ci| ffrt_queue_attr_set_qos(ffrt_queue_attr_t* attr, ffrt_qos_t qos)    | Sets the QoS for a queue attribute.|
111e41f4b71Sopenharmony_ci| ffrt_queue_attr_get_qos(const ffrt_queue_attr_t* attr)      | Obtains the QoS of a queue attribute.|
112e41f4b71Sopenharmony_ci| ffrt_queue_create(ffrt_queue_type_t type, const char* name, const ffrt_queue_attr_t* attr)   | Creates a queue.|
113e41f4b71Sopenharmony_ci| ffrt_queue_destroy(ffrt_queue_t queue)   | Destroys a queue.|
114e41f4b71Sopenharmony_ci| ffrt_queue_submit(ffrt_queue_t queue, ffrt_function_header_t* f, const ffrt_task_attr_t* attr)   | Submits a task to a queue.|
115e41f4b71Sopenharmony_ci| ffrt_queue_submit_h(ffrt_queue_t queue, ffrt_function_header_t* f, const ffrt_task_attr_t* attr)  | Submits a task to a queue, and obtains a task handle.|
116e41f4b71Sopenharmony_ci| ffrt_queue_wait(ffrt_task_handle_t handle)    | Waits until a task in the queue is complete.|
117e41f4b71Sopenharmony_ci| ffrt_queue_cancel(ffrt_task_handle_t handle)     | Cancels a task in the queue.|
118e41f4b71Sopenharmony_ci| ffrt_usleep(uint64_t usec)   | Suspends the calling thread for a given duration.|
119e41f4b71Sopenharmony_ci| ffrt_yield(void)     | Passes control to other tasks so that they can be executed.|
120e41f4b71Sopenharmony_ci| ffrt_task_attr_init(ffrt_task_attr_t* attr)     | Initializes a task attribute.|
121e41f4b71Sopenharmony_ci| ffrt_task_attr_set_name(ffrt_task_attr_t* attr, const char* name)   | Sets a task name.|
122e41f4b71Sopenharmony_ci| ffrt_task_attr_get_name(const ffrt_task_attr_t* attr)   | Obtains a task name.|
123e41f4b71Sopenharmony_ci| ffrt_task_attr_destroy(ffrt_task_attr_t* attr)    | Destroys a task attribute.|
124e41f4b71Sopenharmony_ci| ffrt_task_attr_set_qos(ffrt_task_attr_t* attr, ffrt_qos_t qos)    | Sets the QoS for a task attribute.|
125e41f4b71Sopenharmony_ci| ffrt_task_attr_get_qos(const ffrt_task_attr_t* attr)      | Obtains the QoS of a task attribute.|
126e41f4b71Sopenharmony_ci| ffrt_task_attr_set_delay(ffrt_task_attr_t* attr, uint64_t delay_us)    | Sets the task delay time.|
127e41f4b71Sopenharmony_ci| ffrt_task_attr_get_delay(const ffrt_task_attr_t* attr)      | Obtains the task delay time.|
128e41f4b71Sopenharmony_ci| ffrt_this_task_update_qos(ffrt_qos_t qos)    | Updates the QoS of this task.|
129e41f4b71Sopenharmony_ci| ffrt_this_task_get_id(void)    | Obtains the ID of this task.|
130e41f4b71Sopenharmony_ci| ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_t kind)     | Applies for memory for the function execution structure.|
131e41f4b71Sopenharmony_ci| ffrt_submit_base(ffrt_function_header_t* f, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)   | Submits a task.|
132e41f4b71Sopenharmony_ci| ffrt_submit_h_base(ffrt_function_header_t* f, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)    | Submits a task, and obtains a task handle.|
133e41f4b71Sopenharmony_ci| ffrt_task_handle_destroy(ffrt_task_handle_t handle)    | Destroys a task handle.|
134e41f4b71Sopenharmony_ci| ffrt_skip(ffrt_task_handle_t handle)     | Skips a task.|
135e41f4b71Sopenharmony_ci| ffrt_wait_deps(const ffrt_deps_t* deps)    | Waits until the dependent tasks are complete.|
136e41f4b71Sopenharmony_ci
137e41f4b71Sopenharmony_ci
138e41f4b71Sopenharmony_ci
139e41f4b71Sopenharmony_ci## API Introduction
140e41f4b71Sopenharmony_ci
141e41f4b71Sopenharmony_ci
142e41f4b71Sopenharmony_ci### Task Management APIs
143e41f4b71Sopenharmony_ci
144e41f4b71Sopenharmony_ci#### ffrt_submit_base
145e41f4b71Sopenharmony_ci
146e41f4b71Sopenharmony_ciExports an FFRT dynamic library. You can encapsulate this API into the C API **ffrt_submit** for binary compatibility.
147e41f4b71Sopenharmony_ci
148e41f4b71Sopenharmony_ci##### Declaration
149e41f4b71Sopenharmony_ci
150e41f4b71Sopenharmony_ci```{.c}
151e41f4b71Sopenharmony_ciconst int ffrt_auto_managed_function_storage_size = 64 + sizeof(ffrt_function_header_t);
152e41f4b71Sopenharmony_citypedef enum {
153e41f4b71Sopenharmony_ci    ffrt_function_kind_general,
154e41f4b71Sopenharmony_ci    ffrt_function_kind_queue
155e41f4b71Sopenharmony_ci} ffrt_function_kind_t;
156e41f4b71Sopenharmony_ci
157e41f4b71Sopenharmony_civoid* ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_t kind);
158e41f4b71Sopenharmony_ci
159e41f4b71Sopenharmony_citypedef void(*ffrt_function_t)(void*);
160e41f4b71Sopenharmony_citypedef struct {
161e41f4b71Sopenharmony_ci    ffrt_function_t exec;
162e41f4b71Sopenharmony_ci    ffrt_function_t destroy;
163e41f4b71Sopenharmony_ci    uint64_t reserve[2];
164e41f4b71Sopenharmony_ci} ffrt_function_header_t;
165e41f4b71Sopenharmony_ci
166e41f4b71Sopenharmony_civoid ffrt_submit_base(ffrt_function_header_t* func, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr);
167e41f4b71Sopenharmony_ci```
168e41f4b71Sopenharmony_ci
169e41f4b71Sopenharmony_ci##### Parameters
170e41f4b71Sopenharmony_ci
171e41f4b71Sopenharmony_ci`kind`
172e41f4b71Sopenharmony_ci
173e41f4b71Sopenharmony_ciSubtype of **function**. It is used to optimize the internal data structure. The default value is **ffrt_function_kind_general**.
174e41f4b71Sopenharmony_ci
175e41f4b71Sopenharmony_ci`func`
176e41f4b71Sopenharmony_ci
177e41f4b71Sopenharmony_ciPointer to the CPU function. The struct executed by the pointer describes two function pointers, namely, **exec** and **destroy**, according to the **ffrt_function_header_t** definition. FFRT executes and destroys the task by using the two function pointers.
178e41f4b71Sopenharmony_ci
179e41f4b71Sopenharmony_ci`in_deps`
180e41f4b71Sopenharmony_ci
181e41f4b71Sopenharmony_ci* Optional.
182e41f4b71Sopenharmony_ci* Input dependencies of the task. FFRT establishes the dependency by using the virtual address of the data as the data signature.
183e41f4b71Sopenharmony_ci
184e41f4b71Sopenharmony_ci`out_deps`
185e41f4b71Sopenharmony_ci
186e41f4b71Sopenharmony_ci* Optional.
187e41f4b71Sopenharmony_ci
188e41f4b71Sopenharmony_ci* Output dependencies of the task.
189e41f4b71Sopenharmony_ci
190e41f4b71Sopenharmony_ci  **NOTE**
191e41f4b71Sopenharmony_ci
192e41f4b71Sopenharmony_ci  The dependency is essentially a value. FFRT cannot determine whether the value is reasonable. It always treats the input value reasonable. However, you are not advised to use inappropriate values such as **NULL**, **1**, or **2** to establish dependencies because doing this will establish unnecessary dependencies and affect concurrency. Instead, use the actual memory address.
193e41f4b71Sopenharmony_ci
194e41f4b71Sopenharmony_ci`attr`
195e41f4b71Sopenharmony_ci
196e41f4b71Sopenharmony_ci* Optional.
197e41f4b71Sopenharmony_ci* Task attribute, such as QoS. For details, see [ffrt_task_attr_t](#ffrt_task_attr_t).
198e41f4b71Sopenharmony_ci
199e41f4b71Sopenharmony_ci##### Return value
200e41f4b71Sopenharmony_ci
201e41f4b71Sopenharmony_ciN/A
202e41f4b71Sopenharmony_ci
203e41f4b71Sopenharmony_ci##### Use guide
204e41f4b71Sopenharmony_ci* You are advised to encapsulate **ffrt_submit_base** first. For details, see **Example** below.
205e41f4b71Sopenharmony_ci* As an underlying capability, **ffrt_submit_base** must meet the following requirements:
206e41f4b71Sopenharmony_ci  * The **func** pointer can be allocated by calling **ffrt_alloc_auto_managed_function_storage_base**, and the two function pointers in the struct must be in the specified sequence (**exec** prior to **destroy**).
207e41f4b71Sopenharmony_ci  * The memory allocated by calling **ffrt_alloc_auto_managed_function_storage_base** is of the size specified by **ffrt_auto_managed_function_storage_size**. Its lifecycle is managed by FFRT. When the task is complete, FFRT automatically releases the memory.
208e41f4b71Sopenharmony_ci* The following two function pointers are defined in **ffrt_function_header_t**:
209e41f4b71Sopenharmony_ci  * **exec**: describes how the task is executed. It is called by FFRT to execute the task.
210e41f4b71Sopenharmony_ci  * **destroy**: describes how a task is destroyed. It is called by FFRT to destroy the task.
211e41f4b71Sopenharmony_ci
212e41f4b71Sopenharmony_ci##### Example
213e41f4b71Sopenharmony_ci
214e41f4b71Sopenharmony_ci
215e41f4b71Sopenharmony_ci```{.c}
216e41f4b71Sopenharmony_citemplate<class T>
217e41f4b71Sopenharmony_cistruct function {
218e41f4b71Sopenharmony_ci    template<class CT>
219e41f4b71Sopenharmony_ci    function(ffrt_function_header_t h, CT&& c) : header(h), closure(std::forward<CT>(c)) {}
220e41f4b71Sopenharmony_ci    ffrt_function_header_t header;
221e41f4b71Sopenharmony_ci    T closure;
222e41f4b71Sopenharmony_ci};
223e41f4b71Sopenharmony_ci
224e41f4b71Sopenharmony_citemplate<class T>
225e41f4b71Sopenharmony_civoid exec_function_wrapper(void* t)
226e41f4b71Sopenharmony_ci{
227e41f4b71Sopenharmony_ci    auto f = (function<std::decay_t<T>>*)t;
228e41f4b71Sopenharmony_ci    f->closure();
229e41f4b71Sopenharmony_ci}
230e41f4b71Sopenharmony_ci
231e41f4b71Sopenharmony_citemplate<class T>
232e41f4b71Sopenharmony_civoid destroy_function_wrapper(void* t)
233e41f4b71Sopenharmony_ci{
234e41f4b71Sopenharmony_ci    auto f = (function<std::decay_t<T>>*)t;
235e41f4b71Sopenharmony_ci    f->closure = nullptr;
236e41f4b71Sopenharmony_ci}
237e41f4b71Sopenharmony_ci
238e41f4b71Sopenharmony_citemplate<class T>
239e41f4b71Sopenharmony_ciinline ffrt_function_header_t* create_function_wrapper(T&& func)
240e41f4b71Sopenharmony_ci{
241e41f4b71Sopenharmony_ci    using function_type = function<std::decay_t<T>>;
242e41f4b71Sopenharmony_ci    static_assert(sizeof(function_type) <= ffrt_auto_managed_function_storage_size,
243e41f4b71Sopenharmony_ci        "size of function must be less than ffrt_auto_managed_function_storage_size");
244e41f4b71Sopenharmony_ci
245e41f4b71Sopenharmony_ci    auto p = ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
246e41f4b71Sopenharmony_ci    auto f = new (p) function_type(
247e41f4b71Sopenharmony_ci        {exec_function_wrapper<T>, destroy_function_wrapper<T>},
248e41f4b71Sopenharmony_ci        std::forward<T>(func));
249e41f4b71Sopenharmony_ci    return (ffrt_function_header_t*)f;
250e41f4b71Sopenharmony_ci}
251e41f4b71Sopenharmony_ci
252e41f4b71Sopenharmony_cistatic inline void submit(std::function<void()>&& func)
253e41f4b71Sopenharmony_ci{
254e41f4b71Sopenharmony_ci    return ffrt_submit_base(create_function_wrapper(std::move(func)), NULL, NULL, NULL);
255e41f4b71Sopenharmony_ci}
256e41f4b71Sopenharmony_ci```
257e41f4b71Sopenharmony_ci
258e41f4b71Sopenharmony_ci#### ffrt_wait
259e41f4b71Sopenharmony_ci
260e41f4b71Sopenharmony_ci- Used together with **ffrt_submit_base**.
261e41f4b71Sopenharmony_ci- Waits by suspending the current execution context, until the specified data is produced or all subtasks of the current task are complete.
262e41f4b71Sopenharmony_ci
263e41f4b71Sopenharmony_ci##### Declaration
264e41f4b71Sopenharmony_ci
265e41f4b71Sopenharmony_ci```{.c}
266e41f4b71Sopenharmony_civoid ffrt_wait_deps(ffrt_deps_t* deps);
267e41f4b71Sopenharmony_civoid ffrt_wait();
268e41f4b71Sopenharmony_ci```
269e41f4b71Sopenharmony_ci
270e41f4b71Sopenharmony_ci##### Parameters
271e41f4b71Sopenharmony_ci
272e41f4b71Sopenharmony_ci`deps`
273e41f4b71Sopenharmony_ci
274e41f4b71Sopenharmony_ciVirtual addresses of the data to be produced. These addresses may be used as **out_deps** in **submit()** of some tasks. For details about how to generate the dependency, see **ffrt_deps_t**. Note that a null pointer indicates no dependency.
275e41f4b71Sopenharmony_ci
276e41f4b71Sopenharmony_ci##### Return value
277e41f4b71Sopenharmony_ci
278e41f4b71Sopenharmony_ciN/A
279e41f4b71Sopenharmony_ci
280e41f4b71Sopenharmony_ci##### Use guide
281e41f4b71Sopenharmony_ci* **ffrt_wait_deps(deps)** is used to suspend code execution before the data specified by **deps** is produced.
282e41f4b71Sopenharmony_ci* **ffrt_wait()** is used to suspend code execution before all subtasks (excluding grandchild tasks and lower-level subtasks) submitted by the current context are complete.
283e41f4b71Sopenharmony_ci* This API can be called inside or outside an FFRT task.
284e41f4b71Sopenharmony_ci* **ffrt_wait_deps(deps)** or **ffrt_wait()** called outside an FFRT task can be sensed by the OS, and therefore it is more expensive than that called inside an FFRT task. As such, you are advised to use **ffrt_wait()** inside an FFRT task whenever possible.
285e41f4b71Sopenharmony_ci
286e41f4b71Sopenharmony_ci##### Example
287e41f4b71Sopenharmony_ci
288e41f4b71Sopenharmony_ci**Recursive Fibonacci**
289e41f4b71Sopenharmony_ci
290e41f4b71Sopenharmony_ciThe Fibonacci Sequence implemented in serial mode is as follows:
291e41f4b71Sopenharmony_ci
292e41f4b71Sopenharmony_ci```{.c}
293e41f4b71Sopenharmony_ci#include <stdio.h>
294e41f4b71Sopenharmony_ci
295e41f4b71Sopenharmony_civoid fib(int x, int* y) {
296e41f4b71Sopenharmony_ci    if (x <= 1) {
297e41f4b71Sopenharmony_ci        *y = x;
298e41f4b71Sopenharmony_ci    } else {
299e41f4b71Sopenharmony_ci        int y1, y2;
300e41f4b71Sopenharmony_ci        fib(x - 1, &y1);
301e41f4b71Sopenharmony_ci        fib(x - 2, &y2);
302e41f4b71Sopenharmony_ci        *y = y1 + y2;
303e41f4b71Sopenharmony_ci    }
304e41f4b71Sopenharmony_ci}
305e41f4b71Sopenharmony_ciint main(int narg, char** argv)
306e41f4b71Sopenharmony_ci{
307e41f4b71Sopenharmony_ci    int r;
308e41f4b71Sopenharmony_ci    fib(10, &r);
309e41f4b71Sopenharmony_ci    printf("fibonacci 10: %d\n", r);
310e41f4b71Sopenharmony_ci    return 0;
311e41f4b71Sopenharmony_ci}
312e41f4b71Sopenharmony_ci```
313e41f4b71Sopenharmony_ci
314e41f4b71Sopenharmony_ciUse FFRT to implement the Fibonacci Sequence in parallel mode: (For Fibonacci, the computing workload of a single task is small and parallel acceleration is not required. However, this pattern requires high flexibility of the parallel programming model.)
315e41f4b71Sopenharmony_ci
316e41f4b71Sopenharmony_ci```{.c}
317e41f4b71Sopenharmony_ci#include <stdio.h>
318e41f4b71Sopenharmony_ci#include "ffrt.h" // All header files related to FFRT are included.
319e41f4b71Sopenharmony_ci
320e41f4b71Sopenharmony_citypedef struct {
321e41f4b71Sopenharmony_ci    int x;
322e41f4b71Sopenharmony_ci    int* y;
323e41f4b71Sopenharmony_ci} fib_ffrt_s;
324e41f4b71Sopenharmony_ci
325e41f4b71Sopenharmony_citypedef struct {
326e41f4b71Sopenharmony_ci    ffrt_function_header_t header;
327e41f4b71Sopenharmony_ci    ffrt_function_t func;
328e41f4b71Sopenharmony_ci    ffrt_function_t after_func;
329e41f4b71Sopenharmony_ci    void* arg;
330e41f4b71Sopenharmony_ci} c_function;
331e41f4b71Sopenharmony_ci
332e41f4b71Sopenharmony_cistatic void ffrt_exec_function_wrapper(void* t)
333e41f4b71Sopenharmony_ci{
334e41f4b71Sopenharmony_ci    c_function* f = (c_function*)t;
335e41f4b71Sopenharmony_ci    if (f->func) {
336e41f4b71Sopenharmony_ci        f->func(f->arg);
337e41f4b71Sopenharmony_ci    }
338e41f4b71Sopenharmony_ci}
339e41f4b71Sopenharmony_ci
340e41f4b71Sopenharmony_cistatic void ffrt_destroy_function_wrapper(void* t)
341e41f4b71Sopenharmony_ci{
342e41f4b71Sopenharmony_ci    c_function* f = (c_function*)t;
343e41f4b71Sopenharmony_ci    if (f->after_func) {
344e41f4b71Sopenharmony_ci        f->after_func(f->arg);
345e41f4b71Sopenharmony_ci    }
346e41f4b71Sopenharmony_ci}
347e41f4b71Sopenharmony_ci
348e41f4b71Sopenharmony_ci#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
349e41f4b71Sopenharmony_cistatic inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
350e41f4b71Sopenharmony_ci    const ffrt_function_t after_func, void* arg)
351e41f4b71Sopenharmony_ci{
352e41f4b71Sopenharmony_ci    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
353e41f4b71Sopenharmony_ci        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
354e41f4b71Sopenharmony_ci    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
355e41f4b71Sopenharmony_ci    f->header.exec = ffrt_exec_function_wrapper;
356e41f4b71Sopenharmony_ci    f->header.destroy = ffrt_destroy_function_wrapper;
357e41f4b71Sopenharmony_ci    f->func = func;
358e41f4b71Sopenharmony_ci    f->after_func = after_func;
359e41f4b71Sopenharmony_ci    f->arg = arg;
360e41f4b71Sopenharmony_ci    return (ffrt_function_header_t*)f;
361e41f4b71Sopenharmony_ci}
362e41f4b71Sopenharmony_ci
363e41f4b71Sopenharmony_cistatic inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
364e41f4b71Sopenharmony_ci    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
365e41f4b71Sopenharmony_ci{
366e41f4b71Sopenharmony_ci    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
367e41f4b71Sopenharmony_ci}
368e41f4b71Sopenharmony_ci
369e41f4b71Sopenharmony_civoid fib_ffrt(void* arg)
370e41f4b71Sopenharmony_ci{
371e41f4b71Sopenharmony_ci    fib_ffrt_s* p = (fib_ffrt_s*)arg;
372e41f4b71Sopenharmony_ci    int x = p->x;
373e41f4b71Sopenharmony_ci    int* y = p->y;
374e41f4b71Sopenharmony_ci
375e41f4b71Sopenharmony_ci    if (x <= 1) {
376e41f4b71Sopenharmony_ci        *y = x;
377e41f4b71Sopenharmony_ci    } else {
378e41f4b71Sopenharmony_ci        int y1, y2;
379e41f4b71Sopenharmony_ci        fib_ffrt_s s1 = {x - 1, &y1};
380e41f4b71Sopenharmony_ci        fib_ffrt_s s2 = {x - 2, &y2};
381e41f4b71Sopenharmony_ci        const std::vector<ffrt_dependence_t> dx_deps = {{ffrt_dependence_data, &x}};
382e41f4b71Sopenharmony_ci        ffrt_deps_t dx{static_cast<uint32_t>(dx_deps.size()), dx_deps.data()};
383e41f4b71Sopenharmony_ci        const std::vector<ffrt_dependence_t> dy1_deps = {{ffrt_dependence_data, &y1}};
384e41f4b71Sopenharmony_ci        ffrt_deps_t dy1{static_cast<uint32_t>(dy1_deps.size()), dy1_deps.data()};
385e41f4b71Sopenharmony_ci        const std::vector<ffrt_dependence_t> dy2_deps = {{ffrt_dependence_data, &y2}};
386e41f4b71Sopenharmony_ci        ffrt_deps_t dy2{static_cast<uint32_t>(dy2_deps.size()), dy2_deps.data()};
387e41f4b71Sopenharmony_ci        const std::vector<ffrt_dependence_t> dy12_deps = {{ffrt_dependence_data, &y1}, {ffrt_dependence_data, &y2}};
388e41f4b71Sopenharmony_ci        ffrt_deps_t dy12{static_cast<uint32_t>(dy12_deps.size()), dy12_deps.data()};
389e41f4b71Sopenharmony_ci        ffrt_submit_c(fib_ffrt, NULL, &s1, &dx, &dy1, NULL);
390e41f4b71Sopenharmony_ci        ffrt_submit_c(fib_ffrt, NULL, &s2, &dx, &dy2, NULL);
391e41f4b71Sopenharmony_ci        ffrt_wait_deps(&dy12);
392e41f4b71Sopenharmony_ci        *y = y1 + y2;
393e41f4b71Sopenharmony_ci    }
394e41f4b71Sopenharmony_ci}
395e41f4b71Sopenharmony_ci
396e41f4b71Sopenharmony_ciint main(int narg, char** argv)
397e41f4b71Sopenharmony_ci{
398e41f4b71Sopenharmony_ci    int r;
399e41f4b71Sopenharmony_ci    fib_ffrt_s s = {10, &r};
400e41f4b71Sopenharmony_ci    const std::vector<ffrt_dependence_t> dr_deps = {{ffrt_dependence_data, &r}};
401e41f4b71Sopenharmony_ci    ffrt_deps_t dr{static_cast<uint32_t>(dr_deps.size()), dr_deps.data()};
402e41f4b71Sopenharmony_ci    ffrt_submit_c(fib_ffrt, NULL, &s, NULL, &dr, NULL);
403e41f4b71Sopenharmony_ci    ffrt_wait_deps(&dr);
404e41f4b71Sopenharmony_ci    printf("fibonacci 10: %d\n", r);
405e41f4b71Sopenharmony_ci    return 0;
406e41f4b71Sopenharmony_ci}
407e41f4b71Sopenharmony_ci```
408e41f4b71Sopenharmony_ci
409e41f4b71Sopenharmony_ci**NOTE**
410e41f4b71Sopenharmony_ci
411e41f4b71Sopenharmony_ci(1) fibonacci (x-1) and fibonacci (x-2) are submitted to FFRT as two tasks. After the two tasks are complete, the results are accumulated.
412e41f4b71Sopenharmony_ci
413e41f4b71Sopenharmony_ci(2) A single task can be split into only two subtasks, but the subtasks can be further split. Therefore, the entire computing graph delivers a high DOP, and a call tree is formed between tasks in FFRT.
414e41f4b71Sopenharmony_ci
415e41f4b71Sopenharmony_ci<img src="figures/ffrtfigure2.png" style="zoom:100%" />
416e41f4b71Sopenharmony_ci
417e41f4b71Sopenharmony_ci> **NOTE**
418e41f4b71Sopenharmony_ci>
419e41f4b71Sopenharmony_ci> The preceding implementation requires you to explicitly manage the data lifecycle and encapsulate input parameters, making the code complex.
420e41f4b71Sopenharmony_ci
421e41f4b71Sopenharmony_ci#### ffrt_deps_t
422e41f4b71Sopenharmony_ci
423e41f4b71Sopenharmony_ciAbstraction of dependency arrays in C code, logically equivalent to **std::vector<void*>** in C++ code.
424e41f4b71Sopenharmony_ci
425e41f4b71Sopenharmony_ci##### Declaration
426e41f4b71Sopenharmony_ci
427e41f4b71Sopenharmony_ci```{.c}
428e41f4b71Sopenharmony_citypedef enum {
429e41f4b71Sopenharmony_ci    ffrt_dependence_data,
430e41f4b71Sopenharmony_ci    ffrt_dependence_task,
431e41f4b71Sopenharmony_ci} ffrt_dependence_type_t;
432e41f4b71Sopenharmony_ci
433e41f4b71Sopenharmony_citypedef struct {
434e41f4b71Sopenharmony_ci    ffrt_dependence_type_t type;
435e41f4b71Sopenharmony_ci    const void* ptr;
436e41f4b71Sopenharmony_ci} ffrt_dependence_t;
437e41f4b71Sopenharmony_ci
438e41f4b71Sopenharmony_citypedef struct {
439e41f4b71Sopenharmony_ci    uint32_t len;
440e41f4b71Sopenharmony_ci    const ffrt_dependence_t* items;
441e41f4b71Sopenharmony_ci} ffrt_deps_t;
442e41f4b71Sopenharmony_ci```
443e41f4b71Sopenharmony_ci
444e41f4b71Sopenharmony_ci##### Parameters
445e41f4b71Sopenharmony_ci
446e41f4b71Sopenharmony_ci`len`
447e41f4b71Sopenharmony_ci
448e41f4b71Sopenharmony_ciNumber of dependent signatures. The value must be greater than or equal to 0.
449e41f4b71Sopenharmony_ci
450e41f4b71Sopenharmony_ci`item`
451e41f4b71Sopenharmony_ci
452e41f4b71Sopenharmony_ciPointer to the start address of each signature.
453e41f4b71Sopenharmony_ci
454e41f4b71Sopenharmony_ci`type`
455e41f4b71Sopenharmony_ci
456e41f4b71Sopenharmony_ciDependency type, which can be data dependency or task dependency.
457e41f4b71Sopenharmony_ci
458e41f4b71Sopenharmony_ci`ptr`
459e41f4b71Sopenharmony_ci
460e41f4b71Sopenharmony_ciActual address of the dependent signature content.
461e41f4b71Sopenharmony_ci
462e41f4b71Sopenharmony_ci##### Return value
463e41f4b71Sopenharmony_ci
464e41f4b71Sopenharmony_ciN/A
465e41f4b71Sopenharmony_ci
466e41f4b71Sopenharmony_ci##### Use guide
467e41f4b71Sopenharmony_ci
468e41f4b71Sopenharmony_ci**item** is the start address pointer of each signature. The pointer can point to the heap space or stack space, but the allocated space must be greater than or equal to len * sizeof(ffrt_dependence_t).
469e41f4b71Sopenharmony_ci
470e41f4b71Sopenharmony_ci##### Example
471e41f4b71Sopenharmony_ci
472e41f4b71Sopenharmony_ciCreate a data dependency or task dependency.
473e41f4b71Sopenharmony_ci
474e41f4b71Sopenharmony_ci```{.c}
475e41f4b71Sopenharmony_ci// Create ffrt_deps_t on which the data depends.
476e41f4b71Sopenharmony_ciint x = 0;
477e41f4b71Sopenharmony_ciconst std::vector<ffrt_dependence_t> in_deps = {{ffrt_dependence_data, &x}};
478e41f4b71Sopenharmony_ciffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.data()};
479e41f4b71Sopenharmony_ci
480e41f4b71Sopenharmony_ci// Submit a task, and obtain a task handle.
481e41f4b71Sopenharmony_ciffrt_task_handle_t task = ffrt_submit_h_base(
482e41f4b71Sopenharmony_ci        ffrt_create_function_wrapper(OnePlusForTest, NULL, &a), NULL, NULL, &attr);
483e41f4b71Sopenharmony_ci// Create ffrt_deps_t on which the task depends.
484e41f4b71Sopenharmony_ciconst std::vector<ffrt_dependence_t> wait_deps = {{ffrt_dependence_task, task}};
485e41f4b71Sopenharmony_ciffrt_deps_t wait{static_cast<uint32_t>(wait_deps.size()), wait_deps.data()};
486e41f4b71Sopenharmony_ci```
487e41f4b71Sopenharmony_ci
488e41f4b71Sopenharmony_ci#### ffrt_task_attr_t
489e41f4b71Sopenharmony_ci
490e41f4b71Sopenharmony_ciAuxiliary class for defining task attributes. It is used together with **ffrt_submit_base**.
491e41f4b71Sopenharmony_ci
492e41f4b71Sopenharmony_ci##### Declaration
493e41f4b71Sopenharmony_ci
494e41f4b71Sopenharmony_ci```{.c}
495e41f4b71Sopenharmony_citypedef enum {
496e41f4b71Sopenharmony_ci    ffrt_qos_inherent = -1,
497e41f4b71Sopenharmony_ci    ffrt_qos_background,
498e41f4b71Sopenharmony_ci    ffrt_qos_utility,
499e41f4b71Sopenharmony_ci    ffrt_qos_default,
500e41f4b71Sopenharmony_ci    ffrt_qos_user_initiated,
501e41f4b71Sopenharmony_ci} ffrt_qos_default_t;
502e41f4b71Sopenharmony_ci
503e41f4b71Sopenharmony_citypedef int ffrt_qos_t;
504e41f4b71Sopenharmony_ci
505e41f4b71Sopenharmony_citypedef struct {
506e41f4b71Sopenharmony_ci    uint32_t storage[(ffrt_task_attr_storage_size + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
507e41f4b71Sopenharmony_ci} ffrt_task_attr_t;
508e41f4b71Sopenharmony_citypedef void* ffrt_task_handle_t;
509e41f4b71Sopenharmony_ci
510e41f4b71Sopenharmony_ciint ffrt_task_attr_init(ffrt_task_attr_t* attr);
511e41f4b71Sopenharmony_civoid ffrt_task_attr_destroy(ffrt_task_attr_t* attr);
512e41f4b71Sopenharmony_civoid ffrt_task_attr_set_qos(ffrt_task_attr_t* attr, ffrt_qos_t qos);
513e41f4b71Sopenharmony_ciffrt_qos_t ffrt_task_attr_get_qos(const ffrt_task_attr_t* attr);
514e41f4b71Sopenharmony_civoid ffrt_task_attr_set_name(ffrt_task_attr_t* attr, const char* name);
515e41f4b71Sopenharmony_ciconst char* ffrt_task_attr_get_name(const ffrt_task_attr_t* attr);
516e41f4b71Sopenharmony_civoid ffrt_task_attr_set_delay(ffrt_task_attr_t* attr, uint64_t delay_us);
517e41f4b71Sopenharmony_ciuint64_t ffrt_task_attr_get_delay(const ffrt_task_attr_t* attr);
518e41f4b71Sopenharmony_ci```
519e41f4b71Sopenharmony_ci
520e41f4b71Sopenharmony_ci##### Parameters
521e41f4b71Sopenharmony_ci
522e41f4b71Sopenharmony_ci`attr`
523e41f4b71Sopenharmony_ci
524e41f4b71Sopenharmony_ciHandle of the target task attribute.
525e41f4b71Sopenharmony_ci
526e41f4b71Sopenharmony_ci`qos`
527e41f4b71Sopenharmony_ci
528e41f4b71Sopenharmony_ci* Enumerated type of QoS.
529e41f4b71Sopenharmony_ci* **ffrt_qos_inherent** is a QoS type, indicating that the QoS of the task to be submitted by **ffrt_submit** inherits the QoS of the current task.
530e41f4b71Sopenharmony_ci
531e41f4b71Sopenharmony_ci`delay_us`
532e41f4b71Sopenharmony_ci
533e41f4b71Sopenharmony_ciDelay for executing the task, in μs.
534e41f4b71Sopenharmony_ci
535e41f4b71Sopenharmony_ci##### Return value
536e41f4b71Sopenharmony_ci
537e41f4b71Sopenharmony_ciN/A
538e41f4b71Sopenharmony_ci
539e41f4b71Sopenharmony_ci##### Use guide
540e41f4b71Sopenharmony_ci* The content passed by **attr** is fetched and stored when **ffrt_submit** is being executed. You can destroy the content on receiving the return value of **ffrt_submit**.
541e41f4b71Sopenharmony_ci* Conventions:
542e41f4b71Sopenharmony_ci  * If **task_attr** is not used for QoS setting during task submission, the QoS of the task is **ffrt_qos_default**.
543e41f4b71Sopenharmony_ci  * If **task_attr** is set to **ffrt_qos_inherent** during task submission, the QoS of the task to be submitted is the same as that of the current task. If a task with the **ffrt_qos_inherent** attribute is submitted outside an FFRT task, its QoS is **ffrt_qos_default**.
544e41f4b71Sopenharmony_ci  * In other cases, the QoS value passed in is used.
545e41f4b71Sopenharmony_ci* You need to set the **ffrt_task_attr_t** object to null or destroy the object. For the same **ffrt_task_attr_t** object, **ffrt_task_attr_destroy** can be called only once. Otherwise, undefined behavior may occur.
546e41f4b71Sopenharmony_ci* If **task_attr** is accessed after **ffrt_task_attr_destroy** is called, undefined behavior may occur.
547e41f4b71Sopenharmony_ci
548e41f4b71Sopenharmony_ci##### Example
549e41f4b71Sopenharmony_ci
550e41f4b71Sopenharmony_ciSubmit a task with the QoS set to **ffrt_qos_background**:
551e41f4b71Sopenharmony_ci
552e41f4b71Sopenharmony_ci```{.c}
553e41f4b71Sopenharmony_ci#include <stdio.h>
554e41f4b71Sopenharmony_ci#include "ffrt.h"
555e41f4b71Sopenharmony_ci
556e41f4b71Sopenharmony_civoid my_print(void* arg)
557e41f4b71Sopenharmony_ci{
558e41f4b71Sopenharmony_ci    printf("hello ffrt\n");
559e41f4b71Sopenharmony_ci}
560e41f4b71Sopenharmony_ci
561e41f4b71Sopenharmony_citypedef struct {
562e41f4b71Sopenharmony_ci    ffrt_function_header_t header;
563e41f4b71Sopenharmony_ci    ffrt_function_t func;
564e41f4b71Sopenharmony_ci    ffrt_function_t after_func;
565e41f4b71Sopenharmony_ci    void* arg;
566e41f4b71Sopenharmony_ci} c_function;
567e41f4b71Sopenharmony_ci
568e41f4b71Sopenharmony_cistatic void ffrt_exec_function_wrapper(void* t)
569e41f4b71Sopenharmony_ci{
570e41f4b71Sopenharmony_ci    c_function* f = (c_function*)t;
571e41f4b71Sopenharmony_ci    if (f->func) {
572e41f4b71Sopenharmony_ci        f->func(f->arg);
573e41f4b71Sopenharmony_ci    }
574e41f4b71Sopenharmony_ci}
575e41f4b71Sopenharmony_ci
576e41f4b71Sopenharmony_cistatic void ffrt_destroy_function_wrapper(void* t)
577e41f4b71Sopenharmony_ci{
578e41f4b71Sopenharmony_ci    c_function* f = (c_function*)t;
579e41f4b71Sopenharmony_ci    if (f->after_func) {
580e41f4b71Sopenharmony_ci        f->after_func(f->arg);
581e41f4b71Sopenharmony_ci    }
582e41f4b71Sopenharmony_ci}
583e41f4b71Sopenharmony_ci
584e41f4b71Sopenharmony_ci#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
585e41f4b71Sopenharmony_cistatic inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
586e41f4b71Sopenharmony_ci    const ffrt_function_t after_func, void* arg)
587e41f4b71Sopenharmony_ci{
588e41f4b71Sopenharmony_ci    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
589e41f4b71Sopenharmony_ci        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
590e41f4b71Sopenharmony_ci    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
591e41f4b71Sopenharmony_ci    f->header.exec = ffrt_exec_function_wrapper;
592e41f4b71Sopenharmony_ci    f->header.destroy = ffrt_destroy_function_wrapper;
593e41f4b71Sopenharmony_ci    f->func = func;
594e41f4b71Sopenharmony_ci    f->after_func = after_func;
595e41f4b71Sopenharmony_ci    f->arg = arg;
596e41f4b71Sopenharmony_ci    return (ffrt_function_header_t*)f;
597e41f4b71Sopenharmony_ci}
598e41f4b71Sopenharmony_ci
599e41f4b71Sopenharmony_cistatic inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
600e41f4b71Sopenharmony_ci    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
601e41f4b71Sopenharmony_ci{
602e41f4b71Sopenharmony_ci    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
603e41f4b71Sopenharmony_ci}
604e41f4b71Sopenharmony_ci
605e41f4b71Sopenharmony_ciint main(int narg, char** argv)
606e41f4b71Sopenharmony_ci{
607e41f4b71Sopenharmony_ci    ffrt_task_attr_t attr;
608e41f4b71Sopenharmony_ci    ffrt_task_attr_init(&attr);
609e41f4b71Sopenharmony_ci    ffrt_task_attr_set_qos(&attr, ffrt_qos_background);
610e41f4b71Sopenharmony_ci    ffrt_task_attr_set_delay(&attr, 10000);
611e41f4b71Sopenharmony_ci    ffrt_submit_c(my_print, NULL, NULL, NULL, NULL, &attr);
612e41f4b71Sopenharmony_ci    ffrt_task_attr_destroy(&attr);
613e41f4b71Sopenharmony_ci    ffrt_wait();
614e41f4b71Sopenharmony_ci    return 0;
615e41f4b71Sopenharmony_ci}
616e41f4b71Sopenharmony_ci```
617e41f4b71Sopenharmony_ci
618e41f4b71Sopenharmony_ci
619e41f4b71Sopenharmony_ci
620e41f4b71Sopenharmony_ci
621e41f4b71Sopenharmony_ci#### ffrt_submit_h_base
622e41f4b71Sopenharmony_ci
623e41f4b71Sopenharmony_ciSubmits a task to the scheduler. Different from **ffrt_submit_base**, **ffrt_submit_h_base** returns a task handle. The handle can be used to establish the dependency between tasks or implement synchronization in the **wait** statements.
624e41f4b71Sopenharmony_ci
625e41f4b71Sopenharmony_ci##### Declaration
626e41f4b71Sopenharmony_ci
627e41f4b71Sopenharmony_ci```{.c}
628e41f4b71Sopenharmony_citypedef void* ffrt_task_handle_t;
629e41f4b71Sopenharmony_ci
630e41f4b71Sopenharmony_ciffrt_task_handle_t ffrt_submit_h_base(ffrt_function_t func, void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr);
631e41f4b71Sopenharmony_civoid ffrt_task_handle_destroy(ffrt_task_handle_t handle);
632e41f4b71Sopenharmony_ci```
633e41f4b71Sopenharmony_ci
634e41f4b71Sopenharmony_ci##### Parameters
635e41f4b71Sopenharmony_ci
636e41f4b71Sopenharmony_ci`func`
637e41f4b71Sopenharmony_ci
638e41f4b71Sopenharmony_ciPointer to the CPU function. The struct executed by the pointer describes, two function pointers, namely, **exec** and **destroy**, according to the **ffrt_function_header_t** definition. FFRT executes and destroys the task by using the two function pointers.
639e41f4b71Sopenharmony_ci
640e41f4b71Sopenharmony_ci`in_deps`
641e41f4b71Sopenharmony_ci
642e41f4b71Sopenharmony_ci* Optional.
643e41f4b71Sopenharmony_ci* Input dependencies of the task. FFRT establishes the dependency by using the virtual address of the data as the data signature.
644e41f4b71Sopenharmony_ci
645e41f4b71Sopenharmony_ci`out_deps`
646e41f4b71Sopenharmony_ci
647e41f4b71Sopenharmony_ci* Optional.
648e41f4b71Sopenharmony_ci
649e41f4b71Sopenharmony_ci* Output dependencies of the task.
650e41f4b71Sopenharmony_ci
651e41f4b71Sopenharmony_ci  **NOTE**
652e41f4b71Sopenharmony_ci
653e41f4b71Sopenharmony_ci  The dependency is essentially a value. FFRT cannot determine whether the value is reasonable. It always treats the input value reasonable. However, you are not advised to use inappropriate values such as **NULL**, **1**, or **2** to establish dependencies because doing this will establish unnecessary dependencies and affect concurrency. Instead, use the actual memory address.
654e41f4b71Sopenharmony_ci
655e41f4b71Sopenharmony_ci`attr`
656e41f4b71Sopenharmony_ci
657e41f4b71Sopenharmony_ci* Optional.
658e41f4b71Sopenharmony_ci* Task attribute, such as QoS. For details, see [ffrt_task_attr_t](#ffrt_task_attr_t).
659e41f4b71Sopenharmony_ci
660e41f4b71Sopenharmony_ci##### Return value
661e41f4b71Sopenharmony_ci
662e41f4b71Sopenharmony_ciTake handle. The handle can be used to establish the dependency between tasks or implement synchronization in the wait statements.
663e41f4b71Sopenharmony_ci
664e41f4b71Sopenharmony_ci##### Use guide
665e41f4b71Sopenharmony_ci
666e41f4b71Sopenharmony_ci* **ffrt_task_handle_t** in the C code must be explicitly destroyed by calling **ffrt_task_handle_destroy**.
667e41f4b71Sopenharmony_ci* You need to set the **ffrt_task_handle_t** object in the C code to null or destroy the object. For the same **ffrt_task_handle_t** object, **ffrt_task_handle_destroy** can be called only once. Otherwise, undefined behavior may occur.
668e41f4b71Sopenharmony_ci* If **ffrt_task_handle_t** is accessed after **ffrt_task_handle_destroy** is called, undefined behavior may occur.
669e41f4b71Sopenharmony_ci
670e41f4b71Sopenharmony_ci##### Example
671e41f4b71Sopenharmony_ci
672e41f4b71Sopenharmony_ci```{.c}
673e41f4b71Sopenharmony_ci#include <stdio.h>
674e41f4b71Sopenharmony_ci#include "ffrt.h"
675e41f4b71Sopenharmony_ci
676e41f4b71Sopenharmony_civoid func0(void* arg)
677e41f4b71Sopenharmony_ci{
678e41f4b71Sopenharmony_ci    printf("hello ");
679e41f4b71Sopenharmony_ci}
680e41f4b71Sopenharmony_ci
681e41f4b71Sopenharmony_civoid func1(void* arg)
682e41f4b71Sopenharmony_ci{
683e41f4b71Sopenharmony_ci    (*(int*)arg)++;
684e41f4b71Sopenharmony_ci}
685e41f4b71Sopenharmony_ci
686e41f4b71Sopenharmony_civoid func2(void* arg)
687e41f4b71Sopenharmony_ci{
688e41f4b71Sopenharmony_ci    printf("world, x = %d\n", *(int*)arg);
689e41f4b71Sopenharmony_ci}
690e41f4b71Sopenharmony_ci
691e41f4b71Sopenharmony_civoid func3(void* arg)
692e41f4b71Sopenharmony_ci{
693e41f4b71Sopenharmony_ci    printf("handle wait");
694e41f4b71Sopenharmony_ci    (*(int*)arg)++;
695e41f4b71Sopenharmony_ci}
696e41f4b71Sopenharmony_ci
697e41f4b71Sopenharmony_citypedef struct {
698e41f4b71Sopenharmony_ci    ffrt_function_header_t header;
699e41f4b71Sopenharmony_ci    ffrt_function_t func;
700e41f4b71Sopenharmony_ci    ffrt_function_t after_func;
701e41f4b71Sopenharmony_ci    void* arg;
702e41f4b71Sopenharmony_ci} c_function;
703e41f4b71Sopenharmony_ci
704e41f4b71Sopenharmony_cistatic void ffrt_exec_function_wrapper(void* t)
705e41f4b71Sopenharmony_ci{
706e41f4b71Sopenharmony_ci    c_function* f = (c_function*)t;
707e41f4b71Sopenharmony_ci    if (f->func) {
708e41f4b71Sopenharmony_ci        f->func(f->arg);
709e41f4b71Sopenharmony_ci    }
710e41f4b71Sopenharmony_ci}
711e41f4b71Sopenharmony_ci
712e41f4b71Sopenharmony_cistatic void ffrt_destroy_function_wrapper(void* t)
713e41f4b71Sopenharmony_ci{
714e41f4b71Sopenharmony_ci    c_function* f = (c_function*)t;
715e41f4b71Sopenharmony_ci    if (f->after_func) {
716e41f4b71Sopenharmony_ci        f->after_func(f->arg);
717e41f4b71Sopenharmony_ci    }
718e41f4b71Sopenharmony_ci}
719e41f4b71Sopenharmony_ci
720e41f4b71Sopenharmony_ci#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
721e41f4b71Sopenharmony_cistatic inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
722e41f4b71Sopenharmony_ci    const ffrt_function_t after_func, void* arg)
723e41f4b71Sopenharmony_ci{
724e41f4b71Sopenharmony_ci    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
725e41f4b71Sopenharmony_ci        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
726e41f4b71Sopenharmony_ci    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
727e41f4b71Sopenharmony_ci    f->header.exec = ffrt_exec_function_wrapper;
728e41f4b71Sopenharmony_ci    f->header.destroy = ffrt_destroy_function_wrapper;
729e41f4b71Sopenharmony_ci    f->func = func;
730e41f4b71Sopenharmony_ci    f->after_func = after_func;
731e41f4b71Sopenharmony_ci    f->arg = arg;
732e41f4b71Sopenharmony_ci    return (ffrt_function_header_t*)f;
733e41f4b71Sopenharmony_ci}
734e41f4b71Sopenharmony_ci
735e41f4b71Sopenharmony_cistatic inline ffrt_task_handle_t ffrt_submit_h_c(ffrt_function_t func, const ffrt_function_t after_func,
736e41f4b71Sopenharmony_ci    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
737e41f4b71Sopenharmony_ci{
738e41f4b71Sopenharmony_ci    return ffrt_submit_h_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
739e41f4b71Sopenharmony_ci}
740e41f4b71Sopenharmony_ci
741e41f4b71Sopenharmony_cistatic inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
742e41f4b71Sopenharmony_ci    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
743e41f4b71Sopenharmony_ci{
744e41f4b71Sopenharmony_ci    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
745e41f4b71Sopenharmony_ci}
746e41f4b71Sopenharmony_ci
747e41f4b71Sopenharmony_ci
748e41f4b71Sopenharmony_ciint main(int narg, char** argv)
749e41f4b71Sopenharmony_ci{  
750e41f4b71Sopenharmony_ci    // Handle the work with submit.
751e41f4b71Sopenharmony_ci    ffrt_task_handle_t h = ffrt_submit_h_c(func0, NULL, NULL, NULL, NULL, NULL); // not need some data in this task
752e41f4b71Sopenharmony_ci    int x = 1;
753e41f4b71Sopenharmony_ci    const std::vector<ffrt_dependence_t> in_deps = {{ffrt_dependence_data, &x}};
754e41f4b71Sopenharmony_ci    ffrt_deps_t d2{static_cast<uint32_t>(in_deps.size()), in_deps.data()};
755e41f4b71Sopenharmony_ci
756e41f4b71Sopenharmony_ci    const std::vector<ffrt_dependence_t> out_deps = {{ffrt_dependence_data, &x}};
757e41f4b71Sopenharmony_ci    ffrt_deps_t d1{static_cast<uint32_t>(out_deps.size()), out_deps.data()};
758e41f4b71Sopenharmony_ci
759e41f4b71Sopenharmony_ci    ffrt_submit_c(func1, NULL, &x, NULL, &d1, NULL);
760e41f4b71Sopenharmony_ci    ffrt_submit_c(func2, NULL, &x, &d2, NULL, NULL); // this task depend x and h
761e41f4b71Sopenharmony_ci    ffrt_task_handle_destroy(h);
762e41f4b71Sopenharmony_ci    
763e41f4b71Sopenharmony_ci    // Handle the work with wait.
764e41f4b71Sopenharmony_ci    ffrt_task_handle_t h2 = ffrt_submit_h_c(func3, NULL, &x, NULL, NULL, NULL);
765e41f4b71Sopenharmony_ci
766e41f4b71Sopenharmony_ci    const std::vector<ffrt_dependence_t> wait_deps = {{ffrt_dependence_task, h2}};
767e41f4b71Sopenharmony_ci    ffrt_deps_t d3{static_cast<uint32_t>(wait_deps.size()), wait_deps.data()};
768e41f4b71Sopenharmony_ci    ffrt_wait_deps(&d3);
769e41f4b71Sopenharmony_ci    ffrt_task_handle_destroy(h2);
770e41f4b71Sopenharmony_ci    printf("x = %d", x);
771e41f4b71Sopenharmony_ci    ffrt_wait();
772e41f4b71Sopenharmony_ci    return 0;
773e41f4b71Sopenharmony_ci}
774e41f4b71Sopenharmony_ci```
775e41f4b71Sopenharmony_ci
776e41f4b71Sopenharmony_ciExpected output:
777e41f4b71Sopenharmony_ci
778e41f4b71Sopenharmony_ci```
779e41f4b71Sopenharmony_cihello 
780e41f4b71Sopenharmony_cihandle wait
781e41f4b71Sopenharmony_cix = 2
782e41f4b71Sopenharmony_ciworld, x = 3
783e41f4b71Sopenharmony_ci```
784e41f4b71Sopenharmony_ci
785e41f4b71Sopenharmony_ci
786e41f4b71Sopenharmony_ci
787e41f4b71Sopenharmony_ci#### ffrt_this_task_get_id
788e41f4b71Sopenharmony_ci
789e41f4b71Sopenharmony_ciObtains the ID of this task. This API is used for maintenance and testing. (The task ID is unique, but the task name may be duplicate.)
790e41f4b71Sopenharmony_ci
791e41f4b71Sopenharmony_ci##### Declaration
792e41f4b71Sopenharmony_ci
793e41f4b71Sopenharmony_ci```{.c}
794e41f4b71Sopenharmony_ciuint64_t ffrt_this_task_get_id();
795e41f4b71Sopenharmony_ci```
796e41f4b71Sopenharmony_ci
797e41f4b71Sopenharmony_ci##### Parameters
798e41f4b71Sopenharmony_ci
799e41f4b71Sopenharmony_ciN/A
800e41f4b71Sopenharmony_ci
801e41f4b71Sopenharmony_ci##### Return value
802e41f4b71Sopenharmony_ci
803e41f4b71Sopenharmony_ciID of the task being executed.
804e41f4b71Sopenharmony_ci
805e41f4b71Sopenharmony_ci##### Use guide
806e41f4b71Sopenharmony_ci
807e41f4b71Sopenharmony_ci* If this API is called inside a task, the ID of this task is returned. If this API is called outside a task, **0** is returned.
808e41f4b71Sopenharmony_ci* You can determine whether the function runs on an FFRT or a non-FFRT worker thread based on the return value.
809e41f4b71Sopenharmony_ci* The task ID starts from 1 and is incremented by 1 each time a task is submitted. The task ID contains 64 bits. Even if one million tasks are submitted per second, it takes 292471.2 years to finish one loop.
810e41f4b71Sopenharmony_ci
811e41f4b71Sopenharmony_ci##### Example
812e41f4b71Sopenharmony_ci
813e41f4b71Sopenharmony_ciN/A
814e41f4b71Sopenharmony_ci
815e41f4b71Sopenharmony_ci#### ffrt_this_task_update_qos
816e41f4b71Sopenharmony_ci
817e41f4b71Sopenharmony_ciUpdates the QoS of the task being executed.
818e41f4b71Sopenharmony_ci
819e41f4b71Sopenharmony_ci##### Declaration
820e41f4b71Sopenharmony_ci
821e41f4b71Sopenharmony_ci```{.c}
822e41f4b71Sopenharmony_ciint ffrt_this_task_update_qos(ffrt_qos_t qos);
823e41f4b71Sopenharmony_ci```
824e41f4b71Sopenharmony_ci
825e41f4b71Sopenharmony_ci##### Parameters
826e41f4b71Sopenharmony_ci
827e41f4b71Sopenharmony_ci`qos` 
828e41f4b71Sopenharmony_ci
829e41f4b71Sopenharmony_ciNew QoS.
830e41f4b71Sopenharmony_ci
831e41f4b71Sopenharmony_ci##### Return value
832e41f4b71Sopenharmony_ci
833e41f4b71Sopenharmony_ciReturns **0** if the operation is successful; returns a non-zero value otherwise.
834e41f4b71Sopenharmony_ci
835e41f4b71Sopenharmony_ci##### Use guide
836e41f4b71Sopenharmony_ci
837e41f4b71Sopenharmony_ci* The QoS update takes effect immediately.
838e41f4b71Sopenharmony_ci* If the new QoS is different from the current QoS, the task is blocked and then resumed based on the new QoS.
839e41f4b71Sopenharmony_ci* If the new QoS is the same as the current QoS, the API returns **0** immediately without any processing.
840e41f4b71Sopenharmony_ci* If this API is called not inside a task, a non-zero value is returned. You can ignore the value or perform other operations.
841e41f4b71Sopenharmony_ci
842e41f4b71Sopenharmony_ci##### Example
843e41f4b71Sopenharmony_ci
844e41f4b71Sopenharmony_ciN/A
845e41f4b71Sopenharmony_ci
846e41f4b71Sopenharmony_ci### Serial Queue
847e41f4b71Sopenharmony_ci
848e41f4b71Sopenharmony_ciFFRT provides **queue** to implement capabilities similar to **WorkQueue** in Android. It can deliver excellent performance if being used properly.
849e41f4b71Sopenharmony_ci
850e41f4b71Sopenharmony_ci#### ffrt_queue_attr_t
851e41f4b71Sopenharmony_ci
852e41f4b71Sopenharmony_ci##### Declaration
853e41f4b71Sopenharmony_ci```{.c}
854e41f4b71Sopenharmony_citypedef struct {
855e41f4b71Sopenharmony_ci    uint32_t storage[(ffrt_queue_attr_storage_size + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
856e41f4b71Sopenharmony_ci} ffrt_queue_attr_t;
857e41f4b71Sopenharmony_ci
858e41f4b71Sopenharmony_ciint ffrt_queue_attr_init(ffrt_queue_attr_t* attr);
859e41f4b71Sopenharmony_civoid ffrt_queue_attr_destroy(ffrt_queue_attr_t* attr);
860e41f4b71Sopenharmony_ci```
861e41f4b71Sopenharmony_ci
862e41f4b71Sopenharmony_ci##### Parameters
863e41f4b71Sopenharmony_ci
864e41f4b71Sopenharmony_ci`attr`
865e41f4b71Sopenharmony_ci
866e41f4b71Sopenharmony_ciPointer to the uninitialized **ffrt_queue_attr_t** object.
867e41f4b71Sopenharmony_ci
868e41f4b71Sopenharmony_ci##### Return value
869e41f4b71Sopenharmony_ciReturns **0** if the API is called successfully; returns **-1** otherwise.
870e41f4b71Sopenharmony_ci
871e41f4b71Sopenharmony_ci##### Use guide
872e41f4b71Sopenharmony_ci* An **ffrt_queue_attr_t** object must be created prior to an **ffrt_queue_t** object.
873e41f4b71Sopenharmony_ci* You need to set the **ffrt_queue_attr_t** object to null or destroy the object. For the same **ffrt_queue_attr_t** object, **ffrt_queue_attr_destroy** can be called only once. Otherwise, undefined behavior may occur.
874e41f4b71Sopenharmony_ci* If **ffrt_queue_attr_t** is accessed after **ffrt_queue_attr_destroy** is called, undefined behavior may occur.
875e41f4b71Sopenharmony_ci
876e41f4b71Sopenharmony_ci##### Example
877e41f4b71Sopenharmony_ciSee the example provided in **ffrt_queue_t**.
878e41f4b71Sopenharmony_ci
879e41f4b71Sopenharmony_ci#### ffrt_queue_t
880e41f4b71Sopenharmony_ci
881e41f4b71Sopenharmony_ci##### Declaration
882e41f4b71Sopenharmony_ci```{.c}
883e41f4b71Sopenharmony_citypedef enum { ffrt_queue_serial, ffrt_queue_max } ffrt_queue_type_t;
884e41f4b71Sopenharmony_citypedef void* ffrt_queue_t;
885e41f4b71Sopenharmony_ci
886e41f4b71Sopenharmony_ciffrt_queue_t ffrt_queue_create(ffrt_queue_type_t type, const char* name, const ffrt_queue_attr_t* attr)
887e41f4b71Sopenharmony_civoid ffrt_queue_destroy(ffrt_queue_t queue)
888e41f4b71Sopenharmony_ci```
889e41f4b71Sopenharmony_ci
890e41f4b71Sopenharmony_ci##### Parameters
891e41f4b71Sopenharmony_ci
892e41f4b71Sopenharmony_ci`type`
893e41f4b71Sopenharmony_ci
894e41f4b71Sopenharmony_ciQueue type.
895e41f4b71Sopenharmony_ci
896e41f4b71Sopenharmony_ci`name`
897e41f4b71Sopenharmony_ci
898e41f4b71Sopenharmony_ciPointer to the queue name.
899e41f4b71Sopenharmony_ci
900e41f4b71Sopenharmony_ci`attr`
901e41f4b71Sopenharmony_ci
902e41f4b71Sopenharmony_ciPointer to the queue attribute. For details, see **ffrt_queue_attr_t**.
903e41f4b71Sopenharmony_ci
904e41f4b71Sopenharmony_ci##### Return value
905e41f4b71Sopenharmony_ciReturns the queue created if the API is called successfully; returns a null pointer otherwise.
906e41f4b71Sopenharmony_ci
907e41f4b71Sopenharmony_ci##### Use guide
908e41f4b71Sopenharmony_ci* Tasks submitted to the queue are executed in sequence. If a task is blocked, the execution sequence of the task cannot be ensured.
909e41f4b71Sopenharmony_ci* You need to set the **ffrt_queue_t** object to null or destroy the object. For the same **ffrt_queue_t** object, **ffrt_queue_destroy** can be called only once. Otherwise, undefined behavior may occur.
910e41f4b71Sopenharmony_ci* If **ffrt_queue_t** is accessed after **ffrt_queue_destroy** is called, undefined behavior may occur.
911e41f4b71Sopenharmony_ci
912e41f4b71Sopenharmony_ci##### Example
913e41f4b71Sopenharmony_ci```
914e41f4b71Sopenharmony_ci#include <stdio.h>
915e41f4b71Sopenharmony_ci#include "ffrt.h"
916e41f4b71Sopenharmony_ci
917e41f4b71Sopenharmony_ciusing namespace std;
918e41f4b71Sopenharmony_ci
919e41f4b71Sopenharmony_citemplate<class T>
920e41f4b71Sopenharmony_cistruct Function {
921e41f4b71Sopenharmony_ci    ffrt_function_header_t header;
922e41f4b71Sopenharmony_ci    T closure;
923e41f4b71Sopenharmony_ci};
924e41f4b71Sopenharmony_ci
925e41f4b71Sopenharmony_citemplate<class T>
926e41f4b71Sopenharmony_civoid ExecFunctionWrapper(void* t)
927e41f4b71Sopenharmony_ci{
928e41f4b71Sopenharmony_ci    auto f = reinterpret_cast<Function<std::decay_t<T>>*>(t);
929e41f4b71Sopenharmony_ci    f->closure();
930e41f4b71Sopenharmony_ci}
931e41f4b71Sopenharmony_ci
932e41f4b71Sopenharmony_citemplate<class T>
933e41f4b71Sopenharmony_civoid DestroyFunctionWrapper(void* t)
934e41f4b71Sopenharmony_ci{
935e41f4b71Sopenharmony_ci    auto f = reinterpret_cast<Function<std::decay_t<T>>*>(t);
936e41f4b71Sopenharmony_ci    f = nullptr;
937e41f4b71Sopenharmony_ci}
938e41f4b71Sopenharmony_ci
939e41f4b71Sopenharmony_citemplate<class T>
940e41f4b71Sopenharmony_cistatic inline ffrt_function_header_t* create_function_wrapper(T&& func,
941e41f4b71Sopenharmony_ci    ffrt_function_kind_t kind = ffrt_function_kind_general)
942e41f4b71Sopenharmony_ci{
943e41f4b71Sopenharmony_ci    using function_type = Function<std::decay_t<T>>;
944e41f4b71Sopenharmony_ci    auto p = ffrt_alloc_auto_managed_function_storage_base(kind);
945e41f4b71Sopenharmony_ci    auto f = new (p)function_type;
946e41f4b71Sopenharmony_ci    f->header.exec = ExecFunctionWrapper<T>;
947e41f4b71Sopenharmony_ci    f->header.destroy = DestroyFunctionWrapper<T>;
948e41f4b71Sopenharmony_ci    f->closure = std::forward<T>(func);
949e41f4b71Sopenharmony_ci    return reinterpret_cast<ffrt_function_header_t*>(f);
950e41f4b71Sopenharmony_ci}
951e41f4b71Sopenharmony_ci
952e41f4b71Sopenharmony_ciint main(int narg, char** argv)
953e41f4b71Sopenharmony_ci{
954e41f4b71Sopenharmony_ci    ffrt_queue_attr_t queue_attr;
955e41f4b71Sopenharmony_ci    (void)ffrt_queue_attr_init(&queue_attr);
956e41f4b71Sopenharmony_ci    ffrt_queue_t queue_handle = ffrt_queue_create(ffrt_queue_serial, "test_queue", &queue_attr);
957e41f4b71Sopenharmony_ci    std::function<void()>&& queueFunc = [] () {printf("Task done.\n");};
958e41f4b71Sopenharmony_ci    ffrt_function_header_t* queueFunc_t = create_function_wrapper((queueFunc), ffrt_function_kind_queue);
959e41f4b71Sopenharmony_ci    ffrt_queue_submit(queue_handle, queueFunc_t, nullptr);
960e41f4b71Sopenharmony_ci
961e41f4b71Sopenharmony_ci    ffrt_queue_attr_destroy(&queue_attr);
962e41f4b71Sopenharmony_ci    ffrt_queue_destroy(queue_handle);
963e41f4b71Sopenharmony_ci}
964e41f4b71Sopenharmony_ci```
965e41f4b71Sopenharmony_ci### Synchronization Primitive
966e41f4b71Sopenharmony_ci
967e41f4b71Sopenharmony_ci#### ffrt_mutex_t
968e41f4b71Sopenharmony_ci
969e41f4b71Sopenharmony_ciProvides performance implementation similar to pthread mutex.
970e41f4b71Sopenharmony_ci
971e41f4b71Sopenharmony_ci##### Declaration
972e41f4b71Sopenharmony_ci
973e41f4b71Sopenharmony_ci```{.c}
974e41f4b71Sopenharmony_citypedef enum {
975e41f4b71Sopenharmony_ci    ffrt_error = -1,
976e41f4b71Sopenharmony_ci    ffrt_success = 0,
977e41f4b71Sopenharmony_ci    ffrt_error_nomem = ENOMEM,
978e41f4b71Sopenharmony_ci    ffrt_error_timedout = ETIMEDOUT,
979e41f4b71Sopenharmony_ci    ffrt_error_busy = EBUSY,
980e41f4b71Sopenharmony_ci    ffrt_error_inval = EINVAL
981e41f4b71Sopenharmony_ci} ffrt_error_t;
982e41f4b71Sopenharmony_ci
983e41f4b71Sopenharmony_cistruct ffrt_mutex_t;
984e41f4b71Sopenharmony_ci
985e41f4b71Sopenharmony_ciint ffrt_mutex_init(ffrt_mutex_t* mutex, const ffrt_mutexattr_t* attr);
986e41f4b71Sopenharmony_ciint ffrt_mutex_lock(ffrt_mutex_t* mutex);
987e41f4b71Sopenharmony_ciint ffrt_mutex_unlock(ffrt_mutex_t* mutex);
988e41f4b71Sopenharmony_ciint ffrt_mutex_trylock(ffrt_mutex_t* mutex);
989e41f4b71Sopenharmony_ciint ffrt_mutex_destroy(ffrt_mutex_t* mutex);
990e41f4b71Sopenharmony_ci```
991e41f4b71Sopenharmony_ci
992e41f4b71Sopenharmony_ci##### Parameters
993e41f4b71Sopenharmony_ci
994e41f4b71Sopenharmony_ci`attr`
995e41f4b71Sopenharmony_ci
996e41f4b71Sopenharmony_ciAttribute of the mutex. Set it to a null pointer. This is because FFRT supports only mutex of the basic type currently.
997e41f4b71Sopenharmony_ci
998e41f4b71Sopenharmony_ci`mutex`
999e41f4b71Sopenharmony_ci
1000e41f4b71Sopenharmony_ciPointer to the target mutex.
1001e41f4b71Sopenharmony_ci
1002e41f4b71Sopenharmony_ci##### Return value
1003e41f4b71Sopenharmony_ci
1004e41f4b71Sopenharmony_ciReturns **ffrt_success** if the API is called successfully; returns an error code otherwise.
1005e41f4b71Sopenharmony_ci
1006e41f4b71Sopenharmony_ci##### Use guide
1007e41f4b71Sopenharmony_ci* This API can be called only inside an FFRT task. If it is called outside an FFRT task, undefined behavior may occur.
1008e41f4b71Sopenharmony_ci* The traditional function **pthread_mutex_t** may cause unexpected kernel mode trap when it fails to lock a mutex. **ffrt_mutex_t** solves this problem and therefore provides better performance if used properly.
1009e41f4b71Sopenharmony_ci* Currently, recursion and timing are not supported.
1010e41f4b71Sopenharmony_ci* **ffrt_mutex_t** in the C code must be explicitly created and destroyed by calling **ffrt_mutex_init** and **ffrt_mutex_destroy**, respectively.
1011e41f4b71Sopenharmony_ci* You need to set the **ffrt_mutex_t** object in the C code to null or destroy the object. For the same **ffrt_mutex_t** object, **ffrt_mutex_destroy** can be called only once. Otherwise, undefined behavior may occur.
1012e41f4b71Sopenharmony_ci* If **ffrt_mutex_t** is accessed after **ffrt_mutex_destroy** is called, undefined behavior may occur.
1013e41f4b71Sopenharmony_ci
1014e41f4b71Sopenharmony_ci##### Example
1015e41f4b71Sopenharmony_ci
1016e41f4b71Sopenharmony_ci```{.c}
1017e41f4b71Sopenharmony_ci#include <stdio.h>
1018e41f4b71Sopenharmony_ci#include "ffrt.h"
1019e41f4b71Sopenharmony_ci
1020e41f4b71Sopenharmony_citypedef struct {
1021e41f4b71Sopenharmony_ci    int* sum;
1022e41f4b71Sopenharmony_ci    ffrt_mutex_t* mtx;
1023e41f4b71Sopenharmony_ci} tuple;
1024e41f4b71Sopenharmony_ci
1025e41f4b71Sopenharmony_civoid func(void* arg)
1026e41f4b71Sopenharmony_ci{
1027e41f4b71Sopenharmony_ci    tuple* t = (tuple*)arg;
1028e41f4b71Sopenharmony_ci    
1029e41f4b71Sopenharmony_ci    int ret = ffrt_mutex_lock(t->mtx);
1030e41f4b71Sopenharmony_ci    if (ret != ffrt_success) {
1031e41f4b71Sopenharmony_ci        printf("error\n");
1032e41f4b71Sopenharmony_ci    }
1033e41f4b71Sopenharmony_ci    (*t->sum)++;
1034e41f4b71Sopenharmony_ci    ret = ffrt_mutex_unlock(t->mtx);
1035e41f4b71Sopenharmony_ci    if (ret != ffrt_success) {
1036e41f4b71Sopenharmony_ci        printf("error\n");
1037e41f4b71Sopenharmony_ci    }
1038e41f4b71Sopenharmony_ci}
1039e41f4b71Sopenharmony_ci
1040e41f4b71Sopenharmony_citypedef struct {
1041e41f4b71Sopenharmony_ci    ffrt_function_header_t header;
1042e41f4b71Sopenharmony_ci    ffrt_function_t func;
1043e41f4b71Sopenharmony_ci    ffrt_function_t after_func;
1044e41f4b71Sopenharmony_ci    void* arg;
1045e41f4b71Sopenharmony_ci} c_function;
1046e41f4b71Sopenharmony_ci
1047e41f4b71Sopenharmony_cistatic void ffrt_exec_function_wrapper(void* t)
1048e41f4b71Sopenharmony_ci{
1049e41f4b71Sopenharmony_ci    c_function* f = (c_function*)t;
1050e41f4b71Sopenharmony_ci    if (f->func) {
1051e41f4b71Sopenharmony_ci        f->func(f->arg);
1052e41f4b71Sopenharmony_ci    }
1053e41f4b71Sopenharmony_ci}
1054e41f4b71Sopenharmony_ci
1055e41f4b71Sopenharmony_cistatic void ffrt_destroy_function_wrapper(void* t)
1056e41f4b71Sopenharmony_ci{
1057e41f4b71Sopenharmony_ci    c_function* f = (c_function*)t;
1058e41f4b71Sopenharmony_ci    if (f->after_func) {
1059e41f4b71Sopenharmony_ci        f->after_func(f->arg);
1060e41f4b71Sopenharmony_ci    }
1061e41f4b71Sopenharmony_ci}
1062e41f4b71Sopenharmony_ci
1063e41f4b71Sopenharmony_ci#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
1064e41f4b71Sopenharmony_cistatic inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
1065e41f4b71Sopenharmony_ci    const ffrt_function_t after_func, void* arg)
1066e41f4b71Sopenharmony_ci{
1067e41f4b71Sopenharmony_ci    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
1068e41f4b71Sopenharmony_ci        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
1069e41f4b71Sopenharmony_ci    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
1070e41f4b71Sopenharmony_ci    f->header.exec = ffrt_exec_function_wrapper;
1071e41f4b71Sopenharmony_ci    f->header.destroy = ffrt_destroy_function_wrapper;
1072e41f4b71Sopenharmony_ci    f->func = func;
1073e41f4b71Sopenharmony_ci    f->after_func = after_func;
1074e41f4b71Sopenharmony_ci    f->arg = arg;
1075e41f4b71Sopenharmony_ci    return (ffrt_function_header_t*)f;
1076e41f4b71Sopenharmony_ci}
1077e41f4b71Sopenharmony_ci
1078e41f4b71Sopenharmony_cistatic inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
1079e41f4b71Sopenharmony_ci    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
1080e41f4b71Sopenharmony_ci{
1081e41f4b71Sopenharmony_ci    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
1082e41f4b71Sopenharmony_ci}
1083e41f4b71Sopenharmony_ci
1084e41f4b71Sopenharmony_civoid ffrt_mutex_task(void *)
1085e41f4b71Sopenharmony_ci{
1086e41f4b71Sopenharmony_ci    int sum = 0;
1087e41f4b71Sopenharmony_ci    ffrt_mutex_t mtx;
1088e41f4b71Sopenharmony_ci    tuple t = {&sum, &mtx};
1089e41f4b71Sopenharmony_ci    int ret = ffrt_mutex_init(&mtx, NULL);
1090e41f4b71Sopenharmony_ci    if (ret != ffrt_success) {
1091e41f4b71Sopenharmony_ci        printf("error\n");
1092e41f4b71Sopenharmony_ci    }
1093e41f4b71Sopenharmony_ci    for (int i = 0; i < 10; i++) {
1094e41f4b71Sopenharmony_ci        ffrt_submit_c(func, NULL, &t, NULL, NULL, NULL);
1095e41f4b71Sopenharmony_ci    }
1096e41f4b71Sopenharmony_ci    ffrt_mutex_destroy(&mtx);
1097e41f4b71Sopenharmony_ci    ffrt_wait();
1098e41f4b71Sopenharmony_ci    printf("sum = %d\n", sum);
1099e41f4b71Sopenharmony_ci}
1100e41f4b71Sopenharmony_ci
1101e41f4b71Sopenharmony_ciint main(int narg, char** argv)
1102e41f4b71Sopenharmony_ci{
1103e41f4b71Sopenharmony_ci    int r;
1104e41f4b71Sopenharmony_ci    ffrt_submit_c(ffrt_mutex_task, NULL, NULL, NULL, NULL, NULL);
1105e41f4b71Sopenharmony_ci    ffrt_wait();
1106e41f4b71Sopenharmony_ci    return 0;
1107e41f4b71Sopenharmony_ci}
1108e41f4b71Sopenharmony_ci```
1109e41f4b71Sopenharmony_ci
1110e41f4b71Sopenharmony_ciExpected output:
1111e41f4b71Sopenharmony_ci
1112e41f4b71Sopenharmony_ci```
1113e41f4b71Sopenharmony_cisum=10
1114e41f4b71Sopenharmony_ci```
1115e41f4b71Sopenharmony_ci
1116e41f4b71Sopenharmony_ciThis example is for reference only and is not encouraged in practice.
1117e41f4b71Sopenharmony_ci
1118e41f4b71Sopenharmony_ci
1119e41f4b71Sopenharmony_ci#### ffrt_cond_t
1120e41f4b71Sopenharmony_ci
1121e41f4b71Sopenharmony_ciProvides performance implementation similar to pthread semaphore.
1122e41f4b71Sopenharmony_ci
1123e41f4b71Sopenharmony_ci##### Declaration
1124e41f4b71Sopenharmony_ci
1125e41f4b71Sopenharmony_ci```{.c}
1126e41f4b71Sopenharmony_citypedef enum {
1127e41f4b71Sopenharmony_ci    ffrt_error = -1,
1128e41f4b71Sopenharmony_ci    ffrt_success = 0,
1129e41f4b71Sopenharmony_ci    ffrt_error_nomem = ENOMEM,
1130e41f4b71Sopenharmony_ci    ffrt_error_timedout = ETIMEDOUT,
1131e41f4b71Sopenharmony_ci    ffrt_error_busy = EBUSY,
1132e41f4b71Sopenharmony_ci    ffrt_error_inval = EINVAL
1133e41f4b71Sopenharmony_ci} ffrt_error_t;
1134e41f4b71Sopenharmony_ci
1135e41f4b71Sopenharmony_cistruct ffrt_cond_t;
1136e41f4b71Sopenharmony_ci
1137e41f4b71Sopenharmony_ciint ffrt_cond_init(ffrt_cond_t* cond, const ffrt_condattr_t* attr);
1138e41f4b71Sopenharmony_ciint ffrt_cond_signal(ffrt_cond_t* cond);
1139e41f4b71Sopenharmony_ciint ffrt_cond_broadcast(ffrt_cond_t* cond);
1140e41f4b71Sopenharmony_ciint ffrt_cond_wait(ffrt_cond_t*cond, ffrt_mutex_t* mutex);
1141e41f4b71Sopenharmony_ciint ffrt_cond_timedwait(ffrt_cond_t* cond, ffrt_mutex_t* mutex, const struct timespec* time_point);
1142e41f4b71Sopenharmony_ciint ffrt_cond_destroy(ffrt_cond_t* cond);
1143e41f4b71Sopenharmony_ci```
1144e41f4b71Sopenharmony_ci
1145e41f4b71Sopenharmony_ci##### Parameters
1146e41f4b71Sopenharmony_ci
1147e41f4b71Sopenharmony_ci`cond`
1148e41f4b71Sopenharmony_ci
1149e41f4b71Sopenharmony_ciPointer to the target semaphore.
1150e41f4b71Sopenharmony_ci
1151e41f4b71Sopenharmony_ci`attr`
1152e41f4b71Sopenharmony_ci
1153e41f4b71Sopenharmony_ciPointer to the attribute. A null pointer indicates that the default attribute is used.
1154e41f4b71Sopenharmony_ci
1155e41f4b71Sopenharmony_ci`mutex`
1156e41f4b71Sopenharmony_ci
1157e41f4b71Sopenharmony_ciPointer to the target mutex.
1158e41f4b71Sopenharmony_ci
1159e41f4b71Sopenharmony_ci`time_point`
1160e41f4b71Sopenharmony_ci
1161e41f4b71Sopenharmony_ciPointer to the maximum duration during which the thread is blocked.
1162e41f4b71Sopenharmony_ci
1163e41f4b71Sopenharmony_ci
1164e41f4b71Sopenharmony_ci##### Return value
1165e41f4b71Sopenharmony_ci
1166e41f4b71Sopenharmony_ciReturns **ffrt_success** if the API is successfully called; returns **ffrt_error_timedout** if the maximum duration is reached before the mutex is locked.
1167e41f4b71Sopenharmony_ci
1168e41f4b71Sopenharmony_ci##### Use guide
1169e41f4b71Sopenharmony_ci* This API can be called only inside an FFRT task. If it is called outside an FFRT task, undefined behavior may occur.
1170e41f4b71Sopenharmony_ci* The traditional function **pthread_cond_t** may cause unexpected kernel mode trap when the conditions are not met. **ffrt_cond_t** solves this problem and therefore provides better performance if being used properly.
1171e41f4b71Sopenharmony_ci* **ffrt_cond_t** in the C code must be explicitly created and destroyed by calling **ffrt_cond_init** and **ffrt_cond_destroy**, respectively.
1172e41f4b71Sopenharmony_ci* You need to set the **ffrt_cond_t** object in the C code to null or destroy the object. For the same **ffrt_cond_t** object, **ffrt_cond_destroy** can be called only once. Otherwise, undefined behavior may occur.
1173e41f4b71Sopenharmony_ci* If **ffrt_cond_t** is accessed after **ffrt_cond_destroy** is called, undefined behavior may occur.
1174e41f4b71Sopenharmony_ci
1175e41f4b71Sopenharmony_ci##### Example
1176e41f4b71Sopenharmony_ci
1177e41f4b71Sopenharmony_ci```{.c}
1178e41f4b71Sopenharmony_ci#include <stdio.h>
1179e41f4b71Sopenharmony_ci#include "ffrt.h"
1180e41f4b71Sopenharmony_ci
1181e41f4b71Sopenharmony_citypedef struct {
1182e41f4b71Sopenharmony_ci    ffrt_cond_t* cond;
1183e41f4b71Sopenharmony_ci    int* a;
1184e41f4b71Sopenharmony_ci    ffrt_mutex_t* lock_;
1185e41f4b71Sopenharmony_ci} tuple;
1186e41f4b71Sopenharmony_ci
1187e41f4b71Sopenharmony_civoid func1(void* arg)
1188e41f4b71Sopenharmony_ci{
1189e41f4b71Sopenharmony_ci    tuple* t = (tuple*)arg;
1190e41f4b71Sopenharmony_ci    int ret = ffrt_mutex_lock(t->lock_);
1191e41f4b71Sopenharmony_ci    if (ret != ffrt_success) {
1192e41f4b71Sopenharmony_ci        printf("error\n");
1193e41f4b71Sopenharmony_ci    }
1194e41f4b71Sopenharmony_ci    while (*t->a != 1) {
1195e41f4b71Sopenharmony_ci        ret = ffrt_cond_wait(t->cond, t->lock_);
1196e41f4b71Sopenharmony_ci        if (ret != ffrt_success) {
1197e41f4b71Sopenharmony_ci            printf("error\n");
1198e41f4b71Sopenharmony_ci        }
1199e41f4b71Sopenharmony_ci    }
1200e41f4b71Sopenharmony_ci    ret = ffrt_mutex_unlock(t->lock_);
1201e41f4b71Sopenharmony_ci    if (ret != ffrt_success) {
1202e41f4b71Sopenharmony_ci        printf("error\n");
1203e41f4b71Sopenharmony_ci    }
1204e41f4b71Sopenharmony_ci    printf("a = %d\n", *(t->a));
1205e41f4b71Sopenharmony_ci}
1206e41f4b71Sopenharmony_ci
1207e41f4b71Sopenharmony_civoid func2(void* arg)
1208e41f4b71Sopenharmony_ci{
1209e41f4b71Sopenharmony_ci    tuple* t = (tuple*)arg;
1210e41f4b71Sopenharmony_ci    int ret = ffrt_mutex_lock(t->lock_);
1211e41f4b71Sopenharmony_ci    if (ret != ffrt_success) {
1212e41f4b71Sopenharmony_ci        printf("error\n");
1213e41f4b71Sopenharmony_ci    }
1214e41f4b71Sopenharmony_ci    *(t->a) = 1;
1215e41f4b71Sopenharmony_ci    ret = ffrt_cond_signal(t->cond);
1216e41f4b71Sopenharmony_ci    if (ret != ffrt_success) {
1217e41f4b71Sopenharmony_ci        printf("error\n");
1218e41f4b71Sopenharmony_ci    }
1219e41f4b71Sopenharmony_ci    ret = ffrt_mutex_unlock(t->lock_);
1220e41f4b71Sopenharmony_ci    if (ret != ffrt_success) {
1221e41f4b71Sopenharmony_ci        printf("error\n");
1222e41f4b71Sopenharmony_ci    }
1223e41f4b71Sopenharmony_ci}
1224e41f4b71Sopenharmony_ci
1225e41f4b71Sopenharmony_citypedef struct {
1226e41f4b71Sopenharmony_ci    ffrt_function_header_t header;
1227e41f4b71Sopenharmony_ci    ffrt_function_t func;
1228e41f4b71Sopenharmony_ci    ffrt_function_t after_func;
1229e41f4b71Sopenharmony_ci    void* arg;
1230e41f4b71Sopenharmony_ci} c_function;
1231e41f4b71Sopenharmony_ci
1232e41f4b71Sopenharmony_cistatic void ffrt_exec_function_wrapper(void* t)
1233e41f4b71Sopenharmony_ci{
1234e41f4b71Sopenharmony_ci    c_function* f = (c_function*)t;
1235e41f4b71Sopenharmony_ci    if (f->func) {
1236e41f4b71Sopenharmony_ci        f->func(f->arg);
1237e41f4b71Sopenharmony_ci    }
1238e41f4b71Sopenharmony_ci}
1239e41f4b71Sopenharmony_ci
1240e41f4b71Sopenharmony_cistatic void ffrt_destroy_function_wrapper(void* t)
1241e41f4b71Sopenharmony_ci{
1242e41f4b71Sopenharmony_ci    c_function* f = (c_function*)t;
1243e41f4b71Sopenharmony_ci    if (f->after_func) {
1244e41f4b71Sopenharmony_ci        f->after_func(f->arg);
1245e41f4b71Sopenharmony_ci    }
1246e41f4b71Sopenharmony_ci}
1247e41f4b71Sopenharmony_ci
1248e41f4b71Sopenharmony_ci#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
1249e41f4b71Sopenharmony_cistatic inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
1250e41f4b71Sopenharmony_ci    const ffrt_function_t after_func, void* arg)
1251e41f4b71Sopenharmony_ci{
1252e41f4b71Sopenharmony_ci    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
1253e41f4b71Sopenharmony_ci        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
1254e41f4b71Sopenharmony_ci    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
1255e41f4b71Sopenharmony_ci    f->header.exec = ffrt_exec_function_wrapper;
1256e41f4b71Sopenharmony_ci    f->header.destroy = ffrt_destroy_function_wrapper;
1257e41f4b71Sopenharmony_ci    f->func = func;
1258e41f4b71Sopenharmony_ci    f->after_func = after_func;
1259e41f4b71Sopenharmony_ci    f->arg = arg;
1260e41f4b71Sopenharmony_ci    return (ffrt_function_header_t*)f;
1261e41f4b71Sopenharmony_ci}
1262e41f4b71Sopenharmony_ci
1263e41f4b71Sopenharmony_cistatic inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
1264e41f4b71Sopenharmony_ci    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
1265e41f4b71Sopenharmony_ci{
1266e41f4b71Sopenharmony_ci    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
1267e41f4b71Sopenharmony_ci}
1268e41f4b71Sopenharmony_ci
1269e41f4b71Sopenharmony_civoid ffrt_cv_task(void *)
1270e41f4b71Sopenharmony_ci{
1271e41f4b71Sopenharmony_ci    ffrt_cond_t cond;
1272e41f4b71Sopenharmony_ci    int ret = ffrt_cond_init(&cond, NULL);
1273e41f4b71Sopenharmony_ci    if (ret != ffrt_success) {
1274e41f4b71Sopenharmony_ci        printf("error\n");
1275e41f4b71Sopenharmony_ci    }
1276e41f4b71Sopenharmony_ci    int a = 0;
1277e41f4b71Sopenharmony_ci    ffrt_mutex_t lock_;
1278e41f4b71Sopenharmony_ci    tuple t = {&cond, &a, &lock_};
1279e41f4b71Sopenharmony_ci    ret = ffrt_mutex_init(&lock_, NULL);
1280e41f4b71Sopenharmony_ci    if (ret != ffrt_success) {
1281e41f4b71Sopenharmony_ci        printf("error\n");
1282e41f4b71Sopenharmony_ci    }
1283e41f4b71Sopenharmony_ci    ffrt_submit_c(func1, NULL, &t, NULL, NULL, NULL);
1284e41f4b71Sopenharmony_ci    ffrt_submit_c(func2, NULL, &t, NULL, NULL, NULL);
1285e41f4b71Sopenharmony_ci    ffrt_wait();
1286e41f4b71Sopenharmony_ci    ffrt_cond_destroy(&cond);
1287e41f4b71Sopenharmony_ci    ffrt_mutex_destroy(&lock_);
1288e41f4b71Sopenharmony_ci}
1289e41f4b71Sopenharmony_ci
1290e41f4b71Sopenharmony_ciint main(int narg, char** argv)
1291e41f4b71Sopenharmony_ci{
1292e41f4b71Sopenharmony_ci    ffrt_submit_c(ffrt_cv_task, NULL, NULL, NULL, NULL, NULL);
1293e41f4b71Sopenharmony_ci    ffrt_wait();
1294e41f4b71Sopenharmony_ci    return 0;
1295e41f4b71Sopenharmony_ci}
1296e41f4b71Sopenharmony_ci```
1297e41f4b71Sopenharmony_ci
1298e41f4b71Sopenharmony_ciExpected output:
1299e41f4b71Sopenharmony_ci
1300e41f4b71Sopenharmony_ci```
1301e41f4b71Sopenharmony_cia=1
1302e41f4b71Sopenharmony_ci```
1303e41f4b71Sopenharmony_ci
1304e41f4b71Sopenharmony_ciThis example is for reference only and is not encouraged in practice.
1305e41f4b71Sopenharmony_ci
1306e41f4b71Sopenharmony_ci### Miscellaneous
1307e41f4b71Sopenharmony_ci
1308e41f4b71Sopenharmony_ci#### ffrt_usleep
1309e41f4b71Sopenharmony_ci
1310e41f4b71Sopenharmony_ciProvides performance implementation similar to C11 sleep and Linux usleep.
1311e41f4b71Sopenharmony_ci
1312e41f4b71Sopenharmony_ci##### Declaration
1313e41f4b71Sopenharmony_ci
1314e41f4b71Sopenharmony_ci```{.c}
1315e41f4b71Sopenharmony_ciint ffrt_usleep(uint64_t usec);
1316e41f4b71Sopenharmony_ci```
1317e41f4b71Sopenharmony_ci
1318e41f4b71Sopenharmony_ci##### Parameters
1319e41f4b71Sopenharmony_ci
1320e41f4b71Sopenharmony_ci`usec`
1321e41f4b71Sopenharmony_ci
1322e41f4b71Sopenharmony_ciDuration that the calling thread is suspended, in μs.
1323e41f4b71Sopenharmony_ci
1324e41f4b71Sopenharmony_ci##### Return value
1325e41f4b71Sopenharmony_ci
1326e41f4b71Sopenharmony_ciN/A
1327e41f4b71Sopenharmony_ci
1328e41f4b71Sopenharmony_ci##### Use guide
1329e41f4b71Sopenharmony_ci* This API can be called only inside an FFRT task. If it is called outside an FFRT task, undefined behavior may occur.
1330e41f4b71Sopenharmony_ci* The traditional function **sleep** may cause unexpected kernel mode trap. **ffrt_usleep** solves this problem and therefore provides better performance if used properly.
1331e41f4b71Sopenharmony_ci
1332e41f4b71Sopenharmony_ci##### Example
1333e41f4b71Sopenharmony_ci
1334e41f4b71Sopenharmony_ci```{.c}
1335e41f4b71Sopenharmony_ci#include <time.h>
1336e41f4b71Sopenharmony_ci#include <stdio.h>
1337e41f4b71Sopenharmony_ci#include "ffrt.h"
1338e41f4b71Sopenharmony_ci
1339e41f4b71Sopenharmony_civoid func(void* arg)
1340e41f4b71Sopenharmony_ci{
1341e41f4b71Sopenharmony_ci    time_t current_time = time(NULL);
1342e41f4b71Sopenharmony_ci    printf("Time: %s", ctime(&current_time));
1343e41f4b71Sopenharmony_ci    ffrt_usleep(2000000); // Suspend for 2 seconds
1344e41f4b71Sopenharmony_ci    current_time = time(NULL);
1345e41f4b71Sopenharmony_ci    printf("Time: %s", ctime(&current_time));
1346e41f4b71Sopenharmony_ci}
1347e41f4b71Sopenharmony_ci
1348e41f4b71Sopenharmony_citypedef struct {
1349e41f4b71Sopenharmony_ci    ffrt_function_header_t header;
1350e41f4b71Sopenharmony_ci    ffrt_function_t func;
1351e41f4b71Sopenharmony_ci    ffrt_function_t after_func;
1352e41f4b71Sopenharmony_ci    void* arg;
1353e41f4b71Sopenharmony_ci} c_function;
1354e41f4b71Sopenharmony_ci
1355e41f4b71Sopenharmony_cistatic void ffrt_exec_function_wrapper(void* t)
1356e41f4b71Sopenharmony_ci{
1357e41f4b71Sopenharmony_ci    c_function* f = (c_function*)t;
1358e41f4b71Sopenharmony_ci    if (f->func) {
1359e41f4b71Sopenharmony_ci        f->func(f->arg);
1360e41f4b71Sopenharmony_ci    }
1361e41f4b71Sopenharmony_ci}
1362e41f4b71Sopenharmony_ci
1363e41f4b71Sopenharmony_cistatic void ffrt_destroy_function_wrapper(void* t)
1364e41f4b71Sopenharmony_ci{
1365e41f4b71Sopenharmony_ci    c_function* f = (c_function*)t;
1366e41f4b71Sopenharmony_ci    if (f->after_func) {
1367e41f4b71Sopenharmony_ci        f->after_func(f->arg);
1368e41f4b71Sopenharmony_ci    }
1369e41f4b71Sopenharmony_ci}
1370e41f4b71Sopenharmony_ci
1371e41f4b71Sopenharmony_ci#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
1372e41f4b71Sopenharmony_cistatic inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
1373e41f4b71Sopenharmony_ci    const ffrt_function_t after_func, void* arg)
1374e41f4b71Sopenharmony_ci{
1375e41f4b71Sopenharmony_ci    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
1376e41f4b71Sopenharmony_ci        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
1377e41f4b71Sopenharmony_ci    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
1378e41f4b71Sopenharmony_ci    f->header.exec = ffrt_exec_function_wrapper;
1379e41f4b71Sopenharmony_ci    f->header.destroy = ffrt_destroy_function_wrapper;
1380e41f4b71Sopenharmony_ci    f->func = func;
1381e41f4b71Sopenharmony_ci    f->after_func = after_func;
1382e41f4b71Sopenharmony_ci    f->arg = arg;
1383e41f4b71Sopenharmony_ci    return (ffrt_function_header_t*)f;
1384e41f4b71Sopenharmony_ci}
1385e41f4b71Sopenharmony_ci
1386e41f4b71Sopenharmony_cistatic inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
1387e41f4b71Sopenharmony_ci    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
1388e41f4b71Sopenharmony_ci{
1389e41f4b71Sopenharmony_ci    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
1390e41f4b71Sopenharmony_ci}
1391e41f4b71Sopenharmony_ci
1392e41f4b71Sopenharmony_ciint main(int narg, char** argv)
1393e41f4b71Sopenharmony_ci{
1394e41f4b71Sopenharmony_ci    ffrt_submit_c(func, NULL, NULL, NULL, NULL, NULL);
1395e41f4b71Sopenharmony_ci    ffrt_wait();
1396e41f4b71Sopenharmony_ci    return 0;
1397e41f4b71Sopenharmony_ci}
1398e41f4b71Sopenharmony_ci```
1399e41f4b71Sopenharmony_ci
1400e41f4b71Sopenharmony_ciAn output case is as follows:
1401e41f4b71Sopenharmony_ci
1402e41f4b71Sopenharmony_ci```
1403e41f4b71Sopenharmony_ciTime: Tue Aug 13 15:45:30 2024
1404e41f4b71Sopenharmony_ciTime: Tue Aug 13 15:45:32 2024
1405e41f4b71Sopenharmony_ci```
1406e41f4b71Sopenharmony_ci
1407e41f4b71Sopenharmony_ci#### ffrt_yield
1408e41f4b71Sopenharmony_ci
1409e41f4b71Sopenharmony_ciPasses control to other tasks so that they can be executed. If there is no other task that can be executed, this API is invalid. 
1410e41f4b71Sopenharmony_ci
1411e41f4b71Sopenharmony_ci##### Declaration
1412e41f4b71Sopenharmony_ci
1413e41f4b71Sopenharmony_ci```{.c}
1414e41f4b71Sopenharmony_civoid ffrt_yield();
1415e41f4b71Sopenharmony_ci```
1416e41f4b71Sopenharmony_ci
1417e41f4b71Sopenharmony_ci##### Parameters
1418e41f4b71Sopenharmony_ci
1419e41f4b71Sopenharmony_ciN/A
1420e41f4b71Sopenharmony_ci
1421e41f4b71Sopenharmony_ci##### Return value
1422e41f4b71Sopenharmony_ci
1423e41f4b71Sopenharmony_ciN/A
1424e41f4b71Sopenharmony_ci
1425e41f4b71Sopenharmony_ci##### Use guide
1426e41f4b71Sopenharmony_ci* This API can be called only inside an FFRT task. If it is called outside an FFRT task, undefined behavior may occur.
1427e41f4b71Sopenharmony_ci* The exact behavior of this API depends on the implementation, especially the mechanism and system state of the FFRT scheduler in use.
1428e41f4b71Sopenharmony_ci
1429e41f4b71Sopenharmony_ci##### Example
1430e41f4b71Sopenharmony_ci
1431e41f4b71Sopenharmony_ciN/A
1432e41f4b71Sopenharmony_ci
1433e41f4b71Sopenharmony_ci
1434e41f4b71Sopenharmony_ci## How to Develop
1435e41f4b71Sopenharmony_ci
1436e41f4b71Sopenharmony_ciThe following describes how to use the native APIs provided by FFRT to create parallel tasks and serial queue tasks and destroy corresponding resources.
1437e41f4b71Sopenharmony_ci
1438e41f4b71Sopenharmony_ci**Adding Dynamic Link Libraries**
1439e41f4b71Sopenharmony_ci
1440e41f4b71Sopenharmony_ciAdd the following libraries to **CMakeLists.txt**.
1441e41f4b71Sopenharmony_ci```txt
1442e41f4b71Sopenharmony_cilibffrt.z.so
1443e41f4b71Sopenharmony_ci```
1444e41f4b71Sopenharmony_ci
1445e41f4b71Sopenharmony_ci**Including Header Files**
1446e41f4b71Sopenharmony_ci```c++
1447e41f4b71Sopenharmony_ci#include "ffrt/task.h"
1448e41f4b71Sopenharmony_ci#include "ffrt/type_def.h"
1449e41f4b71Sopenharmony_ci#include "ffrt/condition_variable.h"
1450e41f4b71Sopenharmony_ci#include "ffrt/mutex.h"
1451e41f4b71Sopenharmony_ci#include "ffrt/queue.h"
1452e41f4b71Sopenharmony_ci#include "ffrt/sleep.h"
1453e41f4b71Sopenharmony_ci```
1454e41f4b71Sopenharmony_ci
1455e41f4b71Sopenharmony_ci1. **Encapsulate the function to be executed.**
1456e41f4b71Sopenharmony_ci    ```c++
1457e41f4b71Sopenharmony_ci    // Method 1: Use the template. C++ is supported.
1458e41f4b71Sopenharmony_ci    template<class T>
1459e41f4b71Sopenharmony_ci    struct Function {
1460e41f4b71Sopenharmony_ci        ffrt_function_header_t header;
1461e41f4b71Sopenharmony_ci        T closure;
1462e41f4b71Sopenharmony_ci    };
1463e41f4b71Sopenharmony_ci
1464e41f4b71Sopenharmony_ci    template<class T>
1465e41f4b71Sopenharmony_ci    void ExecFunctionWrapper(void* t)
1466e41f4b71Sopenharmony_ci    {
1467e41f4b71Sopenharmony_ci        auto f = reinterpret_cast<Function<std::decay_t<T>>*>(t);
1468e41f4b71Sopenharmony_ci        f->closure();
1469e41f4b71Sopenharmony_ci    }
1470e41f4b71Sopenharmony_ci
1471e41f4b71Sopenharmony_ci    template<class T>
1472e41f4b71Sopenharmony_ci    void DestroyFunctionWrapper(void* t)
1473e41f4b71Sopenharmony_ci    {
1474e41f4b71Sopenharmony_ci        auto f = reinterpret_cast<Function<std::decay_t<T>>*>(t);
1475e41f4b71Sopenharmony_ci        f->closure = nullptr;
1476e41f4b71Sopenharmony_ci    }
1477e41f4b71Sopenharmony_ci
1478e41f4b71Sopenharmony_ci    template<class T>
1479e41f4b71Sopenharmony_ci    static inline ffrt_function_header_t* create_function_wrapper(T&& func,
1480e41f4b71Sopenharmony_ci        ffrt_function_kind_t kind = ffrt_function_kind_general)
1481e41f4b71Sopenharmony_ci    {
1482e41f4b71Sopenharmony_ci        using function_type = Function<std::decay_t<T>>;
1483e41f4b71Sopenharmony_ci        auto p = ffrt_alloc_auto_managed_function_storage_base(kind);
1484e41f4b71Sopenharmony_ci        auto f = new (p)function_type;
1485e41f4b71Sopenharmony_ci        f->header.exec = ExecFunctionWrapper<T>;
1486e41f4b71Sopenharmony_ci        f->header.destroy = DestroyFunctionWrapper<T>;
1487e41f4b71Sopenharmony_ci        f->closure = std::forward<T>(func);
1488e41f4b71Sopenharmony_ci        return reinterpret_cast<ffrt_function_header_t*>(f);
1489e41f4b71Sopenharmony_ci    }
1490e41f4b71Sopenharmony_ci
1491e41f4b71Sopenharmony_ci    // Method 2
1492e41f4b71Sopenharmony_ci    typedef struct {
1493e41f4b71Sopenharmony_ci        ffrt_function_header_t header;
1494e41f4b71Sopenharmony_ci        ffrt_function_t func;
1495e41f4b71Sopenharmony_ci        ffrt_function_t after_func;
1496e41f4b71Sopenharmony_ci        void* arg;
1497e41f4b71Sopenharmony_ci    } CFunction;
1498e41f4b71Sopenharmony_ci
1499e41f4b71Sopenharmony_ci    static void FfrtExecFunctionWrapper(void* t)
1500e41f4b71Sopenharmony_ci    {
1501e41f4b71Sopenharmony_ci        CFunction* f = static_cast<CFunction*>(t);
1502e41f4b71Sopenharmony_ci        if (f->func) {
1503e41f4b71Sopenharmony_ci            f->func(f->arg);
1504e41f4b71Sopenharmony_ci        }
1505e41f4b71Sopenharmony_ci    }
1506e41f4b71Sopenharmony_ci
1507e41f4b71Sopenharmony_ci    static void FfrtDestroyFunctionWrapper(void* t)
1508e41f4b71Sopenharmony_ci    {
1509e41f4b71Sopenharmony_ci        CFunction* f = static_cast<CFunction*>(t);
1510e41f4b71Sopenharmony_ci        if (f->after_func) {
1511e41f4b71Sopenharmony_ci            f->after_func(f->arg);
1512e41f4b71Sopenharmony_ci        }
1513e41f4b71Sopenharmony_ci    }
1514e41f4b71Sopenharmony_ci
1515e41f4b71Sopenharmony_ci    #define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
1516e41f4b71Sopenharmony_ci    static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
1517e41f4b71Sopenharmony_ci        const ffrt_function_t after_func, void* arg, ffrt_function_kind_t kind_t = ffrt_function_kind_general)
1518e41f4b71Sopenharmony_ci    {
1519e41f4b71Sopenharmony_ci        FFRT_STATIC_ASSERT(sizeof(CFunction) <= ffrt_auto_managed_function_storage_size,
1520e41f4b71Sopenharmony_ci            size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
1521e41f4b71Sopenharmony_ci        CFunction* f = static_cast<CFunction*>(ffrt_alloc_auto_managed_function_storage_base(kind_t));
1522e41f4b71Sopenharmony_ci        f->header.exec = FfrtExecFunctionWrapper;
1523e41f4b71Sopenharmony_ci        f->header.destroy = FfrtDestroyFunctionWrapper;
1524e41f4b71Sopenharmony_ci        f->func = func;
1525e41f4b71Sopenharmony_ci        f->after_func = after_func;
1526e41f4b71Sopenharmony_ci        f->arg = arg;
1527e41f4b71Sopenharmony_ci        return reinterpret_cast<ffrt_function_header_t*>(f);
1528e41f4b71Sopenharmony_ci    }
1529e41f4b71Sopenharmony_ci
1530e41f4b71Sopenharmony_ci    // Example: function to be submitted for execution.
1531e41f4b71Sopenharmony_ci    void OnePlusForTest(void* arg)
1532e41f4b71Sopenharmony_ci    {
1533e41f4b71Sopenharmony_ci        (*static_cast<int*>(arg)) += 1;
1534e41f4b71Sopenharmony_ci    }
1535e41f4b71Sopenharmony_ci    ```
1536e41f4b71Sopenharmony_ci   
1537e41f4b71Sopenharmony_ci2. **Set the task attributes.**
1538e41f4b71Sopenharmony_ci
1539e41f4b71Sopenharmony_ci    Set the task attributes, including the QoS and task name, before submitting the task.
1540e41f4b71Sopenharmony_ci    ```c++
1541e41f4b71Sopenharmony_ci    // ******Initialize the attributes of the parallel task******
1542e41f4b71Sopenharmony_ci    ffrt_task_attr_t attr;
1543e41f4b71Sopenharmony_ci    ffrt_task_attr_init(&attr);
1544e41f4b71Sopenharmony_ci
1545e41f4b71Sopenharmony_ci    // ******Create a serial queue******
1546e41f4b71Sopenharmony_ci
1547e41f4b71Sopenharmony_ci    // Create the attributes of the serial queue.
1548e41f4b71Sopenharmony_ci    ffrt_queue_attr_t queue_attr;
1549e41f4b71Sopenharmony_ci    // Create the handle of the serial queue.
1550e41f4b71Sopenharmony_ci    ffrt_queue_t queue_handle;
1551e41f4b71Sopenharmony_ci
1552e41f4b71Sopenharmony_ci    // Initialize the queue attribute.
1553e41f4b71Sopenharmony_ci    (void)ffrt_queue_attr_init(&queue_attr);
1554e41f4b71Sopenharmony_ci
1555e41f4b71Sopenharmony_ci    // Set the QoS if necessary.
1556e41f4b71Sopenharmony_ci    ffrt_queue_attr_set_qos(&queue_attr, static_cast<ffrt_qos_t>(ffrt_qos_inherit));
1557e41f4b71Sopenharmony_ci    // Set the timeout period (ms) if necessary.
1558e41f4b71Sopenharmony_ci    ffrt_queue_attr_set_timeout(&queue_attr, 10000);
1559e41f4b71Sopenharmony_ci    // Set the timeout callback if necessary.
1560e41f4b71Sopenharmony_ci    int x = 0;
1561e41f4b71Sopenharmony_ci    ffrt_queue_attr_set_callback(&queue_attr, ffrt_create_function_wrapper(OnePlusForTest, NULL, &x,
1562e41f4b71Sopenharmony_ci        ffrt_function_kind_queue));
1563e41f4b71Sopenharmony_ci
1564e41f4b71Sopenharmony_ci    // Initialize the queue based on the attributes.
1565e41f4b71Sopenharmony_ci    queue_handle = ffrt_queue_create(ffrt_queue_serial, "test_queue", &queue_attr);
1566e41f4b71Sopenharmony_ci    ```
1567e41f4b71Sopenharmony_ci
1568e41f4b71Sopenharmony_ci3. **Submit the task.**
1569e41f4b71Sopenharmony_ci    ```c++
1570e41f4b71Sopenharmony_ci    int a = 0;
1571e41f4b71Sopenharmony_ci    // ******Parallel task******
1572e41f4b71Sopenharmony_ci    // Submit the parallel task without obtaining a handle.
1573e41f4b71Sopenharmony_ci    ffrt_submit_base(ffrt_create_function_wrapper(OnePlusForTest, NULL, &a), NULL, NULL, &attr);
1574e41f4b71Sopenharmony_ci    // Submit the parallel task and obtain a handle.
1575e41f4b71Sopenharmony_ci    ffrt_task_handle_t task = ffrt_submit_h_base(
1576e41f4b71Sopenharmony_ci        ffrt_create_function_wrapper(OnePlusForTest, NULL, &a), NULL, NULL, &attr);
1577e41f4b71Sopenharmony_ci
1578e41f4b71Sopenharmony_ci    // ******Serial queue task******
1579e41f4b71Sopenharmony_ci    // Submit the serial queue task without obtaining a handle.
1580e41f4b71Sopenharmony_ci    ffrt_queue_submit(queue_handle, ffrt_create_function_wrapper(OnePlusForTest, nullptr, &a,
1581e41f4b71Sopenharmony_ci        ffrt_function_kind_queue), nullptr);
1582e41f4b71Sopenharmony_ci    // Submit the serial queue task and obtain a handle.
1583e41f4b71Sopenharmony_ci    ffrt_task_handle_t handle = ffrt_queue_submit_h(queue_handle,
1584e41f4b71Sopenharmony_ci        ffrt_create_function_wrapper(OnePlusForTest, nullptr, &a, ffrt_function_kind_queue), nullptr);
1585e41f4b71Sopenharmony_ci
1586e41f4b71Sopenharmony_ci    // Call wait if you need to wait for the execution result.
1587e41f4b71Sopenharmony_ci    const std::vector<ffrt_dependence_t> wait_deps = {{ffrt_dependence_task, task}};
1588e41f4b71Sopenharmony_ci    ffrt_deps_t wait{static_cast<uint32_t>(wait_deps.size()), wait_deps.data()};
1589e41f4b71Sopenharmony_ci    ffrt_wait_deps(&wait);
1590e41f4b71Sopenharmony_ci
1591e41f4b71Sopenharmony_ci    ffrt_queue_wait(handle);
1592e41f4b71Sopenharmony_ci    ```
1593e41f4b71Sopenharmony_ci
1594e41f4b71Sopenharmony_ci4. **Destroy the resources after the task is submitted.**
1595e41f4b71Sopenharmony_ci    ```c++
1596e41f4b71Sopenharmony_ci    // ******Destroy the parallel task******
1597e41f4b71Sopenharmony_ci    ffrt_task_attr_destroy(&attr);
1598e41f4b71Sopenharmony_ci    ffrt_task_handle_destroy(task);
1599e41f4b71Sopenharmony_ci
1600e41f4b71Sopenharmony_ci    // ******Destroy the serial queue task******
1601e41f4b71Sopenharmony_ci    // Destroy the task handle and then the queue.
1602e41f4b71Sopenharmony_ci    ffrt_queue_attr_destroy(&queue_attr);
1603e41f4b71Sopenharmony_ci    ffrt_task_handle_destroy(handle);
1604e41f4b71Sopenharmony_ci    ffrt_queue_destroy(queue_handle);
1605e41f4b71Sopenharmony_ci    ```
1606e41f4b71Sopenharmony_ci
1607e41f4b71Sopenharmony_ci## Suggestions
1608e41f4b71Sopenharmony_ci
1609e41f4b71Sopenharmony_ci### Suggestion 1: Functional programming
1610e41f4b71Sopenharmony_ci
1611e41f4b71Sopenharmony_ciBasic idea: Use functional programming for the calculation process.
1612e41f4b71Sopenharmony_ci
1613e41f4b71Sopenharmony_ci* Use pure functions and encapsulate them to express each step of the process.
1614e41f4b71Sopenharmony_ci* There is no global data access.
1615e41f4b71Sopenharmony_ci* There is no internal state reserved.
1616e41f4b71Sopenharmony_ci* Use **ffrt_submit_base()** to submit a function in asynchronous mode for execution.
1617e41f4b71Sopenharmony_ci* Use **in_deps** and **out_deps** of **ffrt_submit_base()** to specify the data objects to be accessed by the function and the access mode.
1618e41f4b71Sopenharmony_ci* Use **inDeps** and **outDeps** to specify the dependency between tasks to ensure the correctness of program execution.
1619e41f4b71Sopenharmony_ci
1620e41f4b71Sopenharmony_ci> **NOTE**
1621e41f4b71Sopenharmony_ci>
1622e41f4b71Sopenharmony_ci> Using pure functions helps you maximize the parallelism and avoid data races and lock abuse.
1623e41f4b71Sopenharmony_ci
1624e41f4b71Sopenharmony_ciIn practice, you may not use pure functions in certain scenarios, with the following prerequisites:
1625e41f4b71Sopenharmony_ci
1626e41f4b71Sopenharmony_ci* **in_deps** and **out_deps** can ensure the correctness of program execution.
1627e41f4b71Sopenharmony_ci* The lock mechanism provided by FFRT is used to protect access to global variables.
1628e41f4b71Sopenharmony_ci
1629e41f4b71Sopenharmony_ci
1630e41f4b71Sopenharmony_ci### Suggestion 2: Use FFRT APIs
1631e41f4b71Sopenharmony_ci
1632e41f4b71Sopenharmony_ci* Do not use the APIs of the system thread library to create threads in FFRT tasks. Instead, use **ffrt_submit_base** or **ffrt_submit_h_base** to submit tasks.
1633e41f4b71Sopenharmony_ci* Use the lock, condition variable, sleep, and I/O APIs provided by FFRT to replace the APIs of the system thread library.
1634e41f4b71Sopenharmony_ci* Using the APIs of the system thread library may block worker threads and result in extra performance overhead.
1635e41f4b71Sopenharmony_ci
1636e41f4b71Sopenharmony_ci### Suggestion 3: Deadline mechanism
1637e41f4b71Sopenharmony_ci
1638e41f4b71Sopenharmony_ci* Use FFRT APIs in processing flows that feature periodic/repeated execution.
1639e41f4b71Sopenharmony_ci* Use FFRT APIs in processing flows with clear time constraints and is performance critical.
1640e41f4b71Sopenharmony_ci* Use FFRT APIs in relatively large-granularity processing flows, such as the frame processing flow with the 16.6 ms time constraint.
1641e41f4b71Sopenharmony_ci
1642e41f4b71Sopenharmony_ci### Suggestion 4: Migration from the thread model
1643e41f4b71Sopenharmony_ci
1644e41f4b71Sopenharmony_ci* Create a thread instead of creating an FFRT task.
1645e41f4b71Sopenharmony_ci* A thread is logically similar to a task without **in_deps**.
1646e41f4b71Sopenharmony_ci* Identify the dependency between threads and express the dependencies in **in_deps** or **out_deps** of the task.
1647e41f4b71Sopenharmony_ci* Decompose an intra-thread computing process into asynchronous tasks for invoking.
1648e41f4b71Sopenharmony_ci* Use the task dependency and lock mechanism to avoid data races of concurrent tasks.
1649e41f4b71Sopenharmony_ci
1650e41f4b71Sopenharmony_ci## Restrictions
1651e41f4b71Sopenharmony_ci
1652e41f4b71Sopenharmony_ciAfter an FFRT object is initialized in the C code, you are responsible for setting the object to null or destroying the object.
1653e41f4b71Sopenharmony_ci
1654e41f4b71Sopenharmony_ciTo ensure high performance, the C APIs of FFRT do not use a flag to indicate the object destruction status. You need to release resources properly. Repeatedly destroying an object will cause undefined behavior.
1655e41f4b71Sopenharmony_ci
1656e41f4b71Sopenharmony_ciNoncompliant example 1: Repeated calling of **destroy()** may cause unpredictable data damage.
1657e41f4b71Sopenharmony_ci
1658e41f4b71Sopenharmony_ci```{.c}
1659e41f4b71Sopenharmony_ci#include "ffrt.h"
1660e41f4b71Sopenharmony_civoid abnormal_case_1()
1661e41f4b71Sopenharmony_ci{
1662e41f4b71Sopenharmony_ci    ffrt_task_handle_t h = ffrt_submit_h_base([](){printf("Test task running...\n");}, NULL, NULL, NULL, NULL, NULL);
1663e41f4b71Sopenharmony_ci    ...
1664e41f4b71Sopenharmony_ci    ffrt_task_handle_destroy(h);
1665e41f4b71Sopenharmony_ci    ffrt_task_handle_destroy(h); // double free
1666e41f4b71Sopenharmony_ci}
1667e41f4b71Sopenharmony_ci```
1668e41f4b71Sopenharmony_ci
1669e41f4b71Sopenharmony_ciNoncompliant example 2: A memory leak occurs if **destroy()** is not called.
1670e41f4b71Sopenharmony_ci
1671e41f4b71Sopenharmony_ci```{.c}
1672e41f4b71Sopenharmony_ci#include "ffrt.h"
1673e41f4b71Sopenharmony_civoid abnormal_case_2()
1674e41f4b71Sopenharmony_ci{
1675e41f4b71Sopenharmony_ci    ffrt_task_handle_t h = ffrt_submit_h_base([](){printf("Test task running...\n");}, NULL, NULL, NULL, NULL, NULL);
1676e41f4b71Sopenharmony_ci    ...
1677e41f4b71Sopenharmony_ci    // Memory leak
1678e41f4b71Sopenharmony_ci}
1679e41f4b71Sopenharmony_ci```
1680e41f4b71Sopenharmony_ci
1681e41f4b71Sopenharmony_ciRecommended example: Call **destroy()** only once; set the object to null if necessary.
1682e41f4b71Sopenharmony_ci
1683e41f4b71Sopenharmony_ci```{.c}
1684e41f4b71Sopenharmony_ci#include "ffrt.h"
1685e41f4b71Sopenharmony_civoid normal_case()
1686e41f4b71Sopenharmony_ci{
1687e41f4b71Sopenharmony_ci    ffrt_task_handle_t h = ffrt_submit_h_base([](){printf("Test task running...\n");}, NULL, NULL, NULL, NULL, NULL);
1688e41f4b71Sopenharmony_ci    ...
1689e41f4b71Sopenharmony_ci    ffrt_task_handle_destroy(h);
1690e41f4b71Sopenharmony_ci    h = nullptr; // if necessary
1691e41f4b71Sopenharmony_ci}
1692e41f4b71Sopenharmony_ci```
1693