1# Function Flow Runtime Development
2
3## When to Use
4
5Function 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.
6
7This topic walks you through how to implement parallel programming based on the Function Flow programming model and FFRT.
8
9## Available APIs
10
11| API                                                      | Description                                                        |
12| ------------------------------------------------------------ | ------------------------------------------------------------ |
13| ffrt_condattr_init (ffrt_condattr_t* attr) | Initializes a condition variable attribute.|
14| ffrt_condattr_destroy(ffrt_condattr_t* attr)  | Destroys a condition variable attribute.|
15| ffrt_condattr_setclock(ffrt_condattr_t* attr, ffrt_clockid_t clock) | Sets the clock of a condition variable attribute.|
16| ffrt_condattr_getclock(const ffrt_condattr_t* attr, ffrt_clockid_t* clock)        | Obtains the clock of a condition variable attribute.             |
17| ffrt_cond_init(ffrt_cond_t* cond, const ffrt_condattr_t* attr)   | Initializes a condition variable.     |
18| ffrt_cond_signal(ffrt_cond_t* cond)         | Unblocks at least one of the threads that are blocked on a condition variable.|
19| ffrt_cond_broadcast(ffrt_cond_t* cond) | Unblocks all threads currently blocked on a condition variable.|
20| ffrt_cond_wait(ffrt_cond_t* cond, ffrt_mutex_t* mutex)            | Blocks the calling thread on a condition variable.|
21| 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.|
22| ffrt_cond_destroy(ffrt_cond_t* cond)            | Destroys a condition variable.|
23| ffrt_mutex_init(ffrt_mutex_t* mutex, const ffrt_mutexattr_t* attr) | Initializes a mutex.|
24| ffrt_mutex_lock(ffrt_mutex_t* mutex)   | Locks a mutex.|
25| ffrt_mutex_unlock(ffrt_mutex_t* mutex)  | Unlocks a mutex.|
26| ffrt_mutex_trylock(ffrt_mutex_t* mutex)   | Attempts to lock a mutex.|
27| ffrt_mutex_destroy(ffrt_mutex_t* mutex)   | Destroys a mutex.|
28| ffrt_queue_attr_init(ffrt_queue_attr_t* attr)    | Initializes a queue attribute.|
29| ffrt_queue_attr_destroy(ffrt_queue_attr_t* attr)    | Destroys a queue attribute.|
30| ffrt_queue_attr_set_qos(ffrt_queue_attr_t* attr, ffrt_qos_t qos)    | Sets the queue QoS.|
31| ffrt_queue_attr_get_qos(const ffrt_queue_attr_t* attr)      | Obtains the queue QoS.|
32| ffrt_queue_create(ffrt_queue_type_t type, const char* name, const ffrt_queue_attr_t* attr)   | Creates a queue.|
33| ffrt_queue_destroy(ffrt_queue_t queue)   | Destroys a queue.|
34| ffrt_queue_submit(ffrt_queue_t queue, ffrt_function_header_t* f, const ffrt_task_attr_t* attr)   | Submits a task to a queue.|
35| 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 the task handle.|
36| ffrt_queue_wait(ffrt_task_handle_t handle)    | Waits until a task in the queue is complete.|
37| ffrt_queue_cancel(ffrt_task_handle_t handle)     | Cancels a task in the queue.|
38| ffrt_queue_attr_set_max_concurrency(ffrt_queue_attr_t* attr, const int max_concurrency)    | Sets the maximum concurrency for a queue, which must be a concurrent queue.|
39| ffrt_queue_attr_get_max_concurrency(ffrt_queue_attr_t* attr)     | Obtains the maximum concurrency of a queue, which must be a concurrent queue.|
40| ffrt_get_main_queue()     | Obtains the main thread queue.|
41| ffrt_get_current_queue()     | Obtains the ArkTS Worker thread queue.|
42| ffrt_usleep(uint64_t usec)   | Suspends the calling thread for a given duration.|
43| ffrt_yield(void)     | Passes control to other tasks so that they can be executed.|
44| ffrt_task_attr_init(ffrt_task_attr_t* attr)     | Initializes a task attribute.|
45| ffrt_task_attr_set_name(ffrt_task_attr_t* attr, const char* name)   | Sets a task name.|
46| ffrt_task_attr_get_name(const ffrt_task_attr_t* attr)   | Obtains a task name.|
47| ffrt_task_attr_destroy(ffrt_task_attr_t* attr)    | Destroys a task attribute.|
48| ffrt_task_attr_set_qos(ffrt_task_attr_t* attr, ffrt_qos_t qos)    | Sets the task QoS.|
49| ffrt_task_attr_get_qos(const ffrt_task_attr_t* attr)      | Obtains the task QoS.|
50| ffrt_task_attr_set_delay(ffrt_task_attr_t* attr, uint64_t delay_us)    | Sets the task delay time.|
51| ffrt_task_attr_get_delay(const ffrt_task_attr_t* attr)      | Obtains the task delay time.|
52| ffrt_task_attr_set_queue_priority(ffrt_task_attr_t* attr, ffrt_queue_priority_t priority)     | Sets the task priority in the queue.|
53| ffrt_task_attr_get_queue_priority(const ffrt_task_attr_t* attr)      | Obtains the task priority in the queue.|
54| ffrt_this_task_get_qos()      | Obtains the QoS of this task.|
55| ffrt_this_task_update_qos(ffrt_qos_t qos)    | Updates the QoS of this task.|
56| ffrt_this_task_get_id(void)    | Obtains the ID of this task.|
57| ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_t kind)     | Applies for memory for the function execution structure.|
58| 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.|
59| 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 the task handle.|
60| ffrt_task_handle_destroy(ffrt_task_handle_t handle)    | Destroys a task handle.|
61| ffrt_skip(ffrt_task_handle_t handle)     | Skips a task.|
62| ffrt_wait_deps(const ffrt_deps_t* deps)    | Waits until the dependent tasks are complete.|
63| ffrt_loop_create(ffrt_queue_t queue)    | Creates a loop.|
64| ffrt_loop_destroy(ffrt_loop_t loop)    | Destroys a loop.|
65| ffrt_loop_run(ffrt_loop_t loop)    | Runs a loop.|
66| ffrt_loop_stop(ffrt_loop_t loop)    | Stops a loop.|
67| ffrt_loop_epoll_ctl(ffrt_loop_t loop, int op, int fd, uint32_t events, void* data, ffrt_poller_cb cb)    | Manages listening events on a loop.|
68| ffrt_loop_timer_start(ffrt_loop_t loop, uint64_t timeout, void* data, ffrt_timer_cb cb, bool repeat)    | Starts the timer on a loop.|
69| ffrt_loop_timer_stop(ffrt_loop_t loop, ffrt_timer_t handle)   | Stops the timer on a loop.|
70| ffrt_timer_start(ffrt_qos_t qos, uint64_t timeout, void* data, ffrt_timer_cb cb, bool repeat)   | Starts the timer.|
71| ffrt_timer_stop(ffrt_qos_t qos, ffrt_timer_t handle);   | Stops the timer.|
72
73## API Introduction
74
75
76### Task Management APIs
77
78#### ffrt_submit_base
79
80Exports an FFRT dynamic library. You can encapsulate this API into the C API **ffrt_submit** for binary compatibility.
81
82##### Declaration
83
84```{.c}
85const int ffrt_auto_managed_function_storage_size = 64 + sizeof(ffrt_function_header_t);
86typedef enum {
87    ffrt_function_kind_general,
88    ffrt_function_kind_queue
89} ffrt_function_kind_t;
90
91void* ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_t kind);
92
93typedef void(*ffrt_function_t)(void*);
94typedef struct {
95    ffrt_function_t exec;
96    ffrt_function_t destroy;
97    uint64_t reserve[2];
98} ffrt_function_header_t;
99
100void 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);
101```
102
103##### Parameters
104
105`kind`
106
107Subtype of **function**. It is used to optimize the internal data structure. The default value is **ffrt_function_kind_general**.
108
109`func`
110
111Pointer 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.
112
113`in_deps`
114
115* Optional.
116* Input dependencies of the task. FFRT establishes the dependency by using the virtual address of the data as the data signature.
117
118`out_deps`
119
120* Optional.
121
122* Output dependencies of the task.
123
124  **NOTE**
125
126  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.
127
128`attr`
129
130* Optional.
131* Task attribute, such as QoS. For details, see [ffrt_task_attr_t](#ffrt_task_attr_t).
132
133##### Return value
134
135N/A
136
137##### Description
138* You are advised to encapsulate **ffrt_submit_base** first. For details, see **Example** below.
139* As an underlying capability, **ffrt_submit_base** must meet the following requirements:
140  * 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**).
141  * 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.
142* The following two function pointers are defined in **ffrt_function_header_t**:
143  * **exec**: describes how the task is executed. It is called by FFRT to execute the task.
144  * **destroy**: describes how a task is destroyed. It is called by FFRT to destroy the task.
145
146##### Example
147
148
149```{.c}
150template<class T>
151struct function {
152    template<class CT>
153    function(ffrt_function_header_t h, CT&& c) : header(h), closure(std::forward<CT>(c)) {}
154    ffrt_function_header_t header;
155    T closure;
156};
157
158template<class T>
159void exec_function_wrapper(void* t)
160{
161    auto f = (function<std::decay_t<T>>*)t;
162    f->closure();
163}
164
165template<class T>
166void destroy_function_wrapper(void* t)
167{
168    auto f = (function<std::decay_t<T>>*)t;
169    f->closure = nullptr;
170}
171
172template<class T>
173inline ffrt_function_header_t* create_function_wrapper(T&& func)
174{
175    using function_type = function<std::decay_t<T>>;
176    static_assert(sizeof(function_type) <= ffrt_auto_managed_function_storage_size,
177        "size of function must be less than ffrt_auto_managed_function_storage_size");
178
179    auto p = ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
180    auto f = new (p) function_type(
181        {exec_function_wrapper<T>, destroy_function_wrapper<T>},
182        std::forward<T>(func));
183    return (ffrt_function_header_t*)f;
184}
185
186static inline void submit(std::function<void()>&& func)
187{
188    return ffrt_submit_base(create_function_wrapper(std::move(func)), NULL, NULL, NULL);
189}
190```
191
192#### ffrt_wait
193
194- Used together with **ffrt_submit_base**.
195- Waits by suspending the current execution context, until the specified data is produced or all subtasks of the current task are complete.
196
197##### Declaration
198
199```{.c}
200void ffrt_wait_deps(ffrt_deps_t* deps);
201void ffrt_wait();
202```
203
204##### Parameters
205
206`deps`
207
208Virtual 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.
209
210##### Return value
211
212N/A
213
214##### Description
215* **ffrt_wait_deps(deps)** is used to suspend code execution before the data specified by **deps** is produced.
216* **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.
217* This API can be called inside or outside an FFRT task.
218* **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.
219
220##### Example
221
222**Recursive Fibonacci**
223
224The Fibonacci Sequence implemented in serial mode is as follows:
225
226```{.c}
227#include <stdio.h>
228
229void fib(int x, int* y) {
230    if (x <= 1) {
231        *y = x;
232    } else {
233        int y1, y2;
234        fib(x - 1, &y1);
235        fib(x - 2, &y2);
236        *y = y1 + y2;
237    }
238}
239int main(int narg, char** argv)
240{
241    int r;
242    fib(10, &r);
243    printf("fibonacci 10: %d\n", r);
244    return 0;
245}
246```
247
248Use 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.)
249
250```{.c}
251#include <stdio.h>
252#include "ffrt.h" // All header files related to FFRT are included.
253
254typedef struct {
255    int x;
256    int* y;
257} fib_ffrt_s;
258
259typedef struct {
260    ffrt_function_header_t header;
261    ffrt_function_t func;
262    ffrt_function_t after_func;
263    void* arg;
264} c_function;
265
266static void ffrt_exec_function_wrapper(void* t)
267{
268    c_function* f = (c_function*)t;
269    if (f->func) {
270        f->func(f->arg);
271    }
272}
273
274static void ffrt_destroy_function_wrapper(void* t)
275{
276    c_function* f = (c_function*)t;
277    if (f->after_func) {
278        f->after_func(f->arg);
279    }
280}
281
282#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
283static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
284    const ffrt_function_t after_func, void* arg)
285{
286    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
287        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
288    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
289    f->header.exec = ffrt_exec_function_wrapper;
290    f->header.destroy = ffrt_destroy_function_wrapper;
291    f->func = func;
292    f->after_func = after_func;
293    f->arg = arg;
294    return (ffrt_function_header_t*)f;
295}
296
297static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
298    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
299{
300    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
301}
302
303void fib_ffrt(void* arg)
304{
305    fib_ffrt_s* p = (fib_ffrt_s*)arg;
306    int x = p->x;
307    int* y = p->y;
308
309    if (x <= 1) {
310        *y = x;
311    } else {
312        int y1, y2;
313        fib_ffrt_s s1 = {x - 1, &y1};
314        fib_ffrt_s s2 = {x - 2, &y2};
315        const std::vector<ffrt_dependence_t> dx_deps = {{ffrt_dependence_data, &x}};
316        ffrt_deps_t dx{static_cast<uint32_t>(dx_deps.size()), dx_deps.data()};
317        const std::vector<ffrt_dependence_t> dy1_deps = {{ffrt_dependence_data, &y1}};
318        ffrt_deps_t dy1{static_cast<uint32_t>(dy1_deps.size()), dy1_deps.data()};
319        const std::vector<ffrt_dependence_t> dy2_deps = {{ffrt_dependence_data, &y2}};
320        ffrt_deps_t dy2{static_cast<uint32_t>(dy2_deps.size()), dy2_deps.data()};
321        const std::vector<ffrt_dependence_t> dy12_deps = {{ffrt_dependence_data, &y1}, {ffrt_dependence_data, &y2}};
322        ffrt_deps_t dy12{static_cast<uint32_t>(dy12_deps.size()), dy12_deps.data()};
323        ffrt_submit_c(fib_ffrt, NULL, &s1, &dx, &dy1, NULL);
324        ffrt_submit_c(fib_ffrt, NULL, &s2, &dx, &dy2, NULL);
325        ffrt_wait_deps(&dy12);
326        *y = y1 + y2;
327    }
328}
329
330int main(int narg, char** argv)
331{
332    int r;
333    fib_ffrt_s s = {10, &r};
334    const std::vector<ffrt_dependence_t> dr_deps = {{ffrt_dependence_data, &r}};
335    ffrt_deps_t dr{static_cast<uint32_t>(dr_deps.size()), dr_deps.data()};
336    ffrt_submit_c(fib_ffrt, NULL, &s, NULL, &dr, NULL);
337    ffrt_wait_deps(&dr);
338    printf("fibonacci 10: %d\n", r);
339    return 0;
340}
341```
342
343**NOTE**
344
345(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.
346
347(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.
348
349<img src="figures/ffrtfigure2.png" style="zoom:100%" />
350
351> **NOTE**
352>
353> The preceding implementation requires you to explicitly manage the data lifecycle and encapsulate input parameters, making the code complex.
354
355#### ffrt_deps_t
356
357Abstraction of dependency arrays in C code, logically equivalent to **std::vector<void*>** in C++ code.
358
359##### Declaration
360
361```{.c}
362typedef enum {
363    ffrt_dependence_data,
364    ffrt_dependence_task,
365} ffrt_dependence_type_t;
366
367typedef struct {
368    ffrt_dependence_type_t type;
369    const void* ptr;
370} ffrt_dependence_t;
371
372typedef struct {
373    uint32_t len;
374    const ffrt_dependence_t* items;
375} ffrt_deps_t;
376```
377
378##### Parameters
379
380`len`
381
382Number of dependent signatures. The value must be greater than or equal to 0.
383
384`item`
385
386Pointer to the start address of each signature.
387
388`type`
389
390Dependency type, which can be data dependency or task dependency.
391
392`ptr`
393
394Actual address of the dependent signature content.
395
396##### Return value
397
398N/A
399
400##### Description
401
402**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).
403
404##### Example
405
406Create a data dependency or task dependency.
407
408```{.c}
409// Create ffrt_deps_t on which the data depends.
410int x = 0;
411const std::vector<ffrt_dependence_t> in_deps = {{ffrt_dependence_data, &x}};
412ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.data()};
413
414// Submit a task, and obtain a task handle.
415ffrt_task_handle_t task = ffrt_submit_h_base(
416        ffrt_create_function_wrapper(OnePlusForTest, NULL, &a), NULL, NULL, &attr);
417// Create ffrt_deps_t on which the task depends.
418const std::vector<ffrt_dependence_t> wait_deps = {{ffrt_dependence_task, task}};
419ffrt_deps_t wait{static_cast<uint32_t>(wait_deps.size()), wait_deps.data()};
420```
421
422#### ffrt_task_attr_t
423
424Auxiliary class for defining task attributes. It is used together with **ffrt_submit_base**.
425
426##### Declaration
427
428```{.c}
429typedef enum {
430    ffrt_qos_inherent = -1,
431    ffrt_qos_background,
432    ffrt_qos_utility,
433    ffrt_qos_default,
434    ffrt_qos_user_initiated,
435} ffrt_qos_default_t;
436
437typedef int ffrt_qos_t;
438
439typedef struct {
440    uint32_t storage[(ffrt_task_attr_storage_size + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
441} ffrt_task_attr_t;
442typedef void* ffrt_task_handle_t;
443
444int ffrt_task_attr_init(ffrt_task_attr_t* attr);
445void ffrt_task_attr_destroy(ffrt_task_attr_t* attr);
446void ffrt_task_attr_set_qos(ffrt_task_attr_t* attr, ffrt_qos_t qos);
447ffrt_qos_t ffrt_task_attr_get_qos(const ffrt_task_attr_t* attr);
448void ffrt_task_attr_set_name(ffrt_task_attr_t* attr, const char* name);
449const char* ffrt_task_attr_get_name(const ffrt_task_attr_t* attr);
450void ffrt_task_attr_set_delay(ffrt_task_attr_t* attr, uint64_t delay_us);
451uint64_t ffrt_task_attr_get_delay(const ffrt_task_attr_t* attr);
452```
453
454##### Parameters
455
456`attr`
457
458Handle of the target task attribute.
459
460`qos`
461
462* QoS.
463* **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.
464
465`delay_us`
466
467Delay for executing the task, in μs.
468
469##### Return value
470
471N/A
472
473##### Description
474* 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**.
475* Conventions:
476  * If **task_attr** is not used for QoS setting during task submission, the QoS of the task is **ffrt_qos_default**.
477  * 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**.
478  * In other cases, the QoS value passed in is used.
479* 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.
480* If **task_attr** is accessed after **ffrt_task_attr_destroy** is called, undefined behavior may occur.
481
482##### Example
483
484Submit a task with the QoS set to **ffrt_qos_background**:
485
486```{.c}
487#include <stdio.h>
488#include "ffrt.h"
489
490void my_print(void* arg)
491{
492    printf("hello ffrt\n");
493}
494
495typedef struct {
496    ffrt_function_header_t header;
497    ffrt_function_t func;
498    ffrt_function_t after_func;
499    void* arg;
500} c_function;
501
502static void ffrt_exec_function_wrapper(void* t)
503{
504    c_function* f = (c_function*)t;
505    if (f->func) {
506        f->func(f->arg);
507    }
508}
509
510static void ffrt_destroy_function_wrapper(void* t)
511{
512    c_function* f = (c_function*)t;
513    if (f->after_func) {
514        f->after_func(f->arg);
515    }
516}
517
518#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
519static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
520    const ffrt_function_t after_func, void* arg)
521{
522    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
523        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
524    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
525    f->header.exec = ffrt_exec_function_wrapper;
526    f->header.destroy = ffrt_destroy_function_wrapper;
527    f->func = func;
528    f->after_func = after_func;
529    f->arg = arg;
530    return (ffrt_function_header_t*)f;
531}
532
533static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
534    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
535{
536    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
537}
538
539int main(int narg, char** argv)
540{
541    ffrt_task_attr_t attr;
542    ffrt_task_attr_init(&attr);
543    ffrt_task_attr_set_qos(&attr, ffrt_qos_background);
544    ffrt_task_attr_set_delay(&attr, 10000);
545    ffrt_submit_c(my_print, NULL, NULL, NULL, NULL, &attr);
546    ffrt_task_attr_destroy(&attr);
547    ffrt_wait();
548    return 0;
549}
550```
551
552
553
554
555#### ffrt_submit_h_base
556
557Submits 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.
558
559##### Declaration
560
561```{.c}
562typedef void* ffrt_task_handle_t;
563
564ffrt_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);
565void ffrt_task_handle_destroy(ffrt_task_handle_t handle);
566```
567
568##### Parameters
569
570`func`
571
572Pointer 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.
573
574`in_deps`
575
576* Optional.
577* Input dependencies of the task. FFRT establishes the dependency by using the virtual address of the data as the data signature.
578
579`out_deps`
580
581* Optional.
582
583* Output dependencies of the task.
584
585  **NOTE**
586
587  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. Instead, use the actual memory address because inappropriate values will establish unnecessary dependencies and affect concurrency.
588
589`attr`
590
591* Optional.
592* Task attribute, such as QoS. For details, see [ffrt_task_attr_t](#ffrt_task_attr_t).
593
594##### Return value
595
596Take handle. The handle can be used to establish the dependency between tasks or implement synchronization in the wait statements.
597
598##### Description
599
600* **ffrt_task_handle_t** in the C code must be explicitly destroyed by calling **ffrt_task_handle_destroy**.
601* 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.
602* If **ffrt_task_handle_t** is accessed after **ffrt_task_handle_destroy** is called, undefined behavior may occur.
603
604##### Example
605
606```{.c}
607#include <stdio.h>
608#include "ffrt.h"
609
610void func0(void* arg)
611{
612    printf("hello ");
613}
614
615void func1(void* arg)
616{
617    (*(int*)arg)++;
618}
619
620void func2(void* arg)
621{
622    printf("world, x = %d\n", *(int*)arg);
623}
624
625void func3(void* arg)
626{
627    printf("handle wait");
628    (*(int*)arg)++;
629}
630
631typedef struct {
632    ffrt_function_header_t header;
633    ffrt_function_t func;
634    ffrt_function_t after_func;
635    void* arg;
636} c_function;
637
638static void ffrt_exec_function_wrapper(void* t)
639{
640    c_function* f = (c_function*)t;
641    if (f->func) {
642        f->func(f->arg);
643    }
644}
645
646static void ffrt_destroy_function_wrapper(void* t)
647{
648    c_function* f = (c_function*)t;
649    if (f->after_func) {
650        f->after_func(f->arg);
651    }
652}
653
654#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
655static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
656    const ffrt_function_t after_func, void* arg)
657{
658    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
659        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
660    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
661    f->header.exec = ffrt_exec_function_wrapper;
662    f->header.destroy = ffrt_destroy_function_wrapper;
663    f->func = func;
664    f->after_func = after_func;
665    f->arg = arg;
666    return (ffrt_function_header_t*)f;
667}
668
669static inline ffrt_task_handle_t ffrt_submit_h_c(ffrt_function_t func, const ffrt_function_t after_func,
670    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
671{
672    return ffrt_submit_h_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
673}
674
675static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
676    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
677{
678    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
679}
680
681
682int main(int narg, char** argv)
683{
684    // Handle the work with submit.
685    ffrt_task_handle_t h = ffrt_submit_h_c(func0, NULL, NULL, NULL, NULL, NULL); // not need some data in this task
686    int x = 1;
687    const std::vector<ffrt_dependence_t> in_deps = {{ffrt_dependence_data, &x}};
688    ffrt_deps_t d2{static_cast<uint32_t>(in_deps.size()), in_deps.data()};
689
690    const std::vector<ffrt_dependence_t> out_deps = {{ffrt_dependence_data, &x}};
691    ffrt_deps_t d1{static_cast<uint32_t>(out_deps.size()), out_deps.data()};
692
693    ffrt_submit_c(func1, NULL, &x, NULL, &d1, NULL);
694    ffrt_submit_c(func2, NULL, &x, &d2, NULL, NULL); // this task depend x and h
695    ffrt_task_handle_destroy(h);
696
697    // Handle the work with wait.
698    ffrt_task_handle_t h2 = ffrt_submit_h_c(func3, NULL, &x, NULL, NULL, NULL);
699
700    const std::vector<ffrt_dependence_t> wait_deps = {{ffrt_dependence_task, h2}};
701    ffrt_deps_t d3{static_cast<uint32_t>(wait_deps.size()), wait_deps.data()};
702    ffrt_wait_deps(&d3);
703    ffrt_task_handle_destroy(h2);
704    printf("x = %d", x);
705    ffrt_wait();
706    return 0;
707}
708```
709
710Expected output
711
712```
713hello
714handle wait
715x = 2
716world, x = 3
717```
718
719
720
721#### ffrt_this_task_get_id
722
723Obtains 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.)
724
725##### Declaration
726
727```{.c}
728uint64_t ffrt_this_task_get_id();
729```
730
731##### Parameters
732
733N/A
734
735##### Return value
736
737ID of the task being executed.
738
739##### Description
740
741* 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.
742* You can determine whether the function runs on an FFRT or a non-FFRT worker thread based on the return value.
743* 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.
744
745##### Example
746
747N/A
748
749#### ffrt_this_task_update_qos
750
751Updates the QoS of the task being executed.
752
753##### Declaration
754
755```{.c}
756int ffrt_this_task_update_qos(ffrt_qos_t qos);
757```
758
759##### Parameters
760
761`qos`
762
763New QoS.
764
765##### Return value
766
767Returns **0** if the operation is successful; returns a non-zero value otherwise.
768
769##### Description
770
771* The QoS update takes effect immediately.
772* If the new QoS is different from the current QoS, the task is blocked and then resumed based on the new QoS.
773* If the new QoS is the same as the current QoS, the API returns **0** immediately without any processing.
774* If this API is called not inside a task, a non-zero value is returned. You can ignore the value or perform other operations.
775
776##### Example
777
778N/A
779
780#### ffrt_this_task_get_qos
781
782Obtains the QoS of the task being executed.
783
784##### Declaration
785
786```{.c}
787ffrt_qos_t ffrt_this_task_get_qos();
788```
789
790##### Parameters
791
792NA
793
794##### Return value
795
796QoS.
797
798##### Description
799
800N/A
801
802##### Example
803
804```{.c}
805#include "ffrt.h"
806
807int main(int narg, char** argv)
808{
809    static int x = 0;
810    int* xf = &x;
811    void* data = xf;
812    uint64_t timeout1 = 20;
813
814    ffrt::submit([=]() {
815    ffrt_qos_t taskQos = ffrt_this_task_get_qos();
816    ffrt_timer_cb cb;
817    ffrt_timer_start(taskQos, timeout1, data, cb, false);
818    ffrt_usleep(200);
819    }, {}, {});
820    ffrt::wait();
821    return 0;
822}
823
824```
825
826### Serial Queue
827
828Based on the FFRT coroutine scheduling model, the serial queue implements a message queue. Serial tasks are executed in FFRT Worker threads. You do not need to maintain a dedicated thread, making the scheduling overhead lightweight.
829
830#### ffrt_queue_attr_t
831
832##### Declaration
833```{.c}
834typedef struct {
835    uint32_t storage[(ffrt_queue_attr_storage_size + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
836} ffrt_queue_attr_t;
837
838int ffrt_queue_attr_init(ffrt_queue_attr_t* attr);
839void ffrt_queue_attr_destroy(ffrt_queue_attr_t* attr);
840```
841
842##### Parameters
843
844`attr`
845Pointer to the uninitialized **ffrt_queue_attr_t** object.
846
847##### Return value
848Returns **0** if the API is called successfully; returns **-1** otherwise.
849
850##### Description
851* An **ffrt_queue_attr_t** object must be created prior to an **ffrt_queue_t** object.
852* 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.
853* If **ffrt_queue_attr_t** is accessed after **ffrt_queue_attr_destroy** is called, undefined behavior may occur.
854
855##### Example
856See the example provided in **ffrt_queue_t**.
857
858#### ffrt_queue_t
859
860##### Declaration
861```{.c}
862typedef enum { ffrt_queue_serial, ffrt_queue_concurrent, ffrt_queue_max } ffrt_queue_type_t;
863typedef void* ffrt_queue_t;
864
865ffrt_queue_t ffrt_queue_create(ffrt_queue_type_t type, const char* name, const ffrt_queue_attr_t* attr)
866void ffrt_queue_destroy(ffrt_queue_t queue)
867```
868
869##### Parameters
870
871`type`
872
873Queue type.
874
875`name`
876
877Pointer to the queue name.
878
879`attr`
880
881Pointer to the queue attribute. For details, see **ffrt_queue_attr_t**.
882
883##### Return value
884Returns the queue created if the API is called successfully; returns a null pointer otherwise.
885
886##### Description
887* Tasks submitted to the queue are executed in sequence. If a task is blocked, the execution sequence of the task cannot be ensured.
888* 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.
889* If **ffrt_queue_t** is accessed after **ffrt_queue_destroy** is called, undefined behavior may occur.
890
891##### Example
892```
893#include <stdio.h>
894#include "ffrt.h"
895
896using namespace std;
897
898template<class T>
899struct Function {
900    ffrt_function_header_t header;
901    T closure;
902};
903
904template<class T>
905void ExecFunctionWrapper(void* t)
906{
907    auto f = reinterpret_cast<Function<std::decay_t<T>>*>(t);
908    f->closure();
909}
910
911template<class T>
912void DestroyFunctionWrapper(void* t)
913{
914    auto f = reinterpret_cast<Function<std::decay_t<T>>*>(t);
915    f = nullptr;
916}
917
918template<class T>
919static inline ffrt_function_header_t* create_function_wrapper(T&& func,
920    ffrt_function_kind_t kind = ffrt_function_kind_general)
921{
922    using function_type = Function<std::decay_t<T>>;
923    auto p = ffrt_alloc_auto_managed_function_storage_base(kind);
924    auto f = new (p)function_type;
925    f->header.exec = ExecFunctionWrapper<T>;
926    f->header.destroy = DestroyFunctionWrapper<T>;
927    f->closure = std::forward<T>(func);
928    return reinterpret_cast<ffrt_function_header_t*>(f);
929}
930
931int main(int narg, char** argv)
932{
933    ffrt_queue_attr_t queue_attr;
934    (void)ffrt_queue_attr_init(&queue_attr);
935    ffrt_queue_t queue_handle = ffrt_queue_create(ffrt_queue_serial, "test_queue", &queue_attr);
936    std::function<void()>&& queueFunc = [] () {printf("Task done.\n");};
937    ffrt_function_header_t* queueFunc_t = create_function_wrapper((queueFunc), ffrt_function_kind_queue);
938    ffrt_queue_submit(queue_handle, queueFunc_t, nullptr);
939
940    ffrt_queue_attr_destroy(&queue_attr);
941    ffrt_queue_destroy(queue_handle);
942}
943```
944
945#### ffrt_get_main_queue
946
947Obtains the main thread queue.
948
949##### Declaration
950```{.c}
951ffrt_queue_t ffrt_get_main_queue();
952```
953
954##### Parameters
955
956NA
957
958##### Return value
959
960Main thread queue.
961
962##### Description
963
964The main thread queue is obtained for the FFRT thread to communicate with the main thread.
965
966##### Example
967```{.c}
968This test case must be executed on HarmonyOS.
969#include "ffrt.h"
970
971inline void OnePlusForTest(void* data)
972{
973    *(int*)data += 1;
974}
975
976int main(int narg, char** argv)
977{
978    ffrt::queue *serialQueue = new ffrt::queue("ffrt_normal_queue", {});
979    ffrt_queue_t mainQueue = ffrt_get_main_queue();
980    ffrt_task_attr_t attr;
981    ffrt_task_attr_init(&attr);
982    ffrt_task_attr_set_qos(&attr, ffrt_qos_user_initiated);
983    int result = 0;
984    std::function<void()>&& basicFunc = [&result]() {
985        OnePlusForTest(static_cast<void*>(&result));
986        OnePlusForTest(static_cast<void*>(&result));
987        ffrt_usleep(3000);
988    };
989
990    ffrt::task_handle handle = serialQueue->submit_h(
991        [&] {
992            result = result + 1;
993            ffrt_queue_submit(mainQueue, ffrt::create_function_wrapper(basicFunc, ffrt_function_kind_queue),
994                            &attr);
995        },
996        ffrt::task_attr().qos(3).name("ffrt main_queue."));
997
998    serialQueue->wait(handle);
999    return 0;
1000}
1001```
1002
1003#### ffrt_get_current_queue
1004
1005Obtains the ArkTS Worker thread queue.
1006
1007##### Declaration
1008```{.c}
1009ffrt_queue_t ffrt_get_current_queue();
1010```
1011
1012##### Parameters
1013
1014NA
1015
1016##### Return value
1017
1018ArkTS Worker thread queue.
1019
1020##### Description
1021
1022The ArkTS Worker thread queue is obtained for the FFRT thread to communicate with the ArkTS Worker thread.
1023
1024##### Example
1025```{.c}
1026// This test case must be executed on HarmonyOS.
1027#include "ffrt.h"
1028
1029inline void OnePlusForTest(void* data)
1030{
1031    *(int*)data += 1;
1032}
1033
1034int main(int narg, char** argv)
1035{
1036    ffrt::queue *serialQueue = new ffrt::queue("ffrt_normal_queue", {});
1037    ffrt_queue_t currentQueue = ffrt_get_current_queue();
1038    ffrt_task_attr_t attr;
1039    ffrt_task_attr_init(&attr);
1040    ffrt_task_attr_set_qos(&attr, ffrt_qos_user_initiated);
1041    int result = 0;
1042    std::function<void()>&& basicFunc = [&result]() {
1043        OnePlusForTest(static_cast<void*>(&result));
1044        OnePlusForTest(static_cast<void*>(&result));
1045        ffrt_usleep(3000);
1046    };
1047
1048    ffrt::task_handle handle = serialQueue->submit_h(
1049        [&] {
1050            result = result + 1;
1051            ffrt_queue_submit(currentQueue, ffrt::create_function_wrapper(basicFunc, ffrt_function_kind_queue),
1052                            &attr);
1053        },
1054        ffrt::task_attr().qos(3).name("ffrt current_queue."));
1055
1056    serialQueue->wait(handle);
1057    return 0;
1058}
1059```
1060
1061
1062### Concurrent Queue
1063
1064FFRT supports concurrent queues and allows you to set the concurrency and task priority of a concurrent queue.
1065
1066#### ffrt_queue_attr_set_max_concurrency
1067
1068Sets the maximum concurrency for a queue, which must be a concurrent queue.
1069
1070##### Declaration
1071```{.c}
1072void ffrt_queue_attr_set_max_concurrency(ffrt_queue_attr_t* attr, const int max_concurrency);
1073```
1074
1075##### Parameters
1076
1077`attr`
1078
1079Pointer to the queue attribute. For details, see **ffrt_queue_attr_t**.
1080
1081`max_concurrency`
1082
1083Maximum concurrency. If the parameter is set to a value less than or equal to 0, the concurrency 1 is used.
1084
1085##### Return value
1086
1087NA
1088
1089##### Description
1090
1091If the concurrency is set to a large value, for example, 100, the actual concurrency may fail to reach the set value due to hardware capability limitations.
1092
1093##### Example
1094```{.c}
1095#include "ffrt.h"
1096
1097int main(int narg, char** argv)
1098{
1099    ffrt_queue_attr_t queue_attr;
1100    (void)ffrt_queue_attr_init(&queue_attr);
1101    uint64_t concurrency = 4;
1102    ffrt_queue_attr_set_max_concurrency(&queue_attr, concurrency);
1103    concurrency = ffrt_queue_attr_get_max_concurrency(&queue_attr);
1104    ffrt_queue_attr_destroy(&queue_attr);
1105    printf("concurrency=%lu\n", concurrency);
1106    return 0;
1107}
1108```
1109
1110Expected output
1111
1112```
1113concurrency=4
1114```
1115
1116#### ffrt_queue_attr_get_max_concurrency
1117
1118Obtains the maximum concurrency of a queue, which must be a concurrent queue.
1119
1120##### Declaration
1121```{.c}
1122int ffrt_queue_attr_get_max_concurrency(const ffrt_queue_attr_t* attr);
1123```
1124
1125##### Parameters
1126
1127`attr`
1128
1129Pointer to the queue attribute. For details, see **ffrt_queue_attr_t**.
1130
1131##### Return value
1132
1133Maximum concurrency.
1134
1135##### Description
1136N/A
1137
1138##### Example
1139```{.c}
1140#include "ffrt.h"
1141
1142int main(int narg, char** argv)
1143{
1144    ffrt_queue_attr_t queue_attr;
1145    (void)ffrt_queue_attr_init(&queue_attr);
1146    uint64_t concurrency = 4;
1147    ffrt_queue_attr_set_max_concurrency(&queue_attr, concurrency);
1148    concurrency = ffrt_queue_attr_get_max_concurrency(&queue_attr);
1149    ffrt_queue_attr_destroy(&queue_attr);
1150    printf("concurrency=%lu\n", concurrency);
1151    return 0;
1152}
1153```
1154
1155Expected output
1156
1157```
1158concurrency=4
1159```
1160
1161#### ffrt_task_attr_set_queue_priority
1162<hr/>
1163Sets the task priority in the queue.
1164
1165##### Declaration
1166```{.c}
1167/* Task priority */
1168typedef enum {
1169ffrt_queue_priority_immediate = 0,
1170ffrt_queue_priority_high,
1171ffrt_queue_priority_low,
1172ffrt_queue_priority_idle,
1173} ffrt_queue_priority_t;
1174
1175void ffrt_task_attr_set_queue_priority(ffrt_task_attr_t* attr, ffrt_queue_priority_t priority);
1176```
1177
1178##### Parameters
1179
1180`attr`
1181
1182Pointer to the task attribute. For details, see **ffrt_task_attr_t**.
1183
1184`priority`
1185
1186Task priority. Four priorities are supported. For details, see **ffrt_queue_priority_t**.
1187
1188##### Return value
1189
1190NA
1191
1192##### Description
1193N/A
1194
1195##### Example
1196```{.c}
1197#include "ffrt.h"
1198
1199int main(int narg, char** argv)
1200{
1201    ffrt_task_attr_t task_attr;
1202    (void)ffrt_task_attr_init(&task_attr);
1203    ffrt_queue_priority_t priority = ffrt_queue_priority_idle;
1204    ffrt_task_attr_set_queue_priority(&task_attr, priority);
1205    priority = ffrt_task_attr_get_queue_priority(&task_attr);
1206    ffrt_task_attr_destroy(&task_attr);
1207    printf("priority=%d\n", priority);
1208    return 0;
1209}
1210```
1211
1212Expected output
1213
1214```
1215priority=3
1216```
1217
1218#### ffrt_task_attr_get_queue_priority
1219
1220Obtains the task priority in a queue.
1221
1222##### Declaration
1223```{.c}
1224ffrt_queue_priority_t ffrt_task_attr_get_queue_priority(const ffrt_task_attr_t* attr);
1225```
1226
1227##### Parameters
1228
1229`attr`
1230
1231Pointer to the queue attribute. For details, see **ffrt_queue_attr_t**.
1232
1233##### Return value
1234
1235Task priority.
1236
1237##### Description
1238N/A
1239
1240##### Example
1241```{.c}
1242#include "ffrt.h"
1243
1244int main(int narg, char** argv)
1245{
1246    ffrt_task_attr_t task_attr;
1247    (void)ffrt_task_attr_init(&task_attr);
1248    ffrt_queue_priority_t priority = ffrt_queue_priority_idle;
1249    ffrt_task_attr_set_queue_priority(&task_attr, priority);
1250    priority = ffrt_task_attr_get_queue_priority(&task_attr);
1251    ffrt_task_attr_destroy(&task_attr);
1252    printf("priority=%d\n", priority);
1253    return 0;
1254}
1255```
1256
1257Expected output
1258
1259```
1260priority=3
1261```
1262
1263### Synchronization Primitive
1264
1265#### ffrt_mutex_t
1266
1267Provides performance implementation similar to pthread mutex.
1268
1269##### Declaration
1270
1271```{.c}
1272typedef enum {
1273    ffrt_error = -1,
1274    ffrt_success = 0,
1275    ffrt_error_nomem = ENOMEM,
1276    ffrt_error_timedout = ETIMEDOUT,
1277    ffrt_error_busy = EBUSY,
1278    ffrt_error_inval = EINVAL
1279} ffrt_error_t;
1280
1281struct ffrt_mutex_t;
1282
1283int ffrt_mutex_init(ffrt_mutex_t* mutex, const ffrt_mutexattr_t* attr);
1284int ffrt_mutex_lock(ffrt_mutex_t* mutex);
1285int ffrt_mutex_unlock(ffrt_mutex_t* mutex);
1286int ffrt_mutex_trylock(ffrt_mutex_t* mutex);
1287int ffrt_mutex_destroy(ffrt_mutex_t* mutex);
1288```
1289
1290##### Parameters
1291
1292`attr`
1293
1294Attribute of the mutex. Set it to a null pointer. This is because FFRT supports only mutex of the basic type currently.
1295
1296`mutex`
1297
1298Pointer to the target mutex.
1299
1300##### Return value
1301
1302Returns **ffrt_success** if the API is called successfully; returns an error code otherwise.
1303
1304##### Description
1305* This API can be called only inside an FFRT task. If it is called outside an FFRT task, undefined behavior may occur.
1306* 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.
1307* Currently, recursion and timing are not supported.
1308* **ffrt_mutex_t** in the C code must be explicitly created and destroyed by calling **ffrt_mutex_init** and **ffrt_mutex_destroy**, respectively.
1309* 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.
1310* If **ffrt_mutex_t** is accessed after **ffrt_mutex_destroy** is called, undefined behavior may occur.
1311
1312##### Example
1313
1314```{.c}
1315#include <stdio.h>
1316#include "ffrt.h"
1317
1318typedef struct {
1319    int* sum;
1320    ffrt_mutex_t* mtx;
1321} tuple;
1322
1323void func(void* arg)
1324{
1325    tuple* t = (tuple*)arg;
1326
1327    int ret = ffrt_mutex_lock(t->mtx);
1328    if (ret != ffrt_success) {
1329        printf("error\n");
1330    }
1331    (*t->sum)++;
1332    ret = ffrt_mutex_unlock(t->mtx);
1333    if (ret != ffrt_success) {
1334        printf("error\n");
1335    }
1336}
1337
1338typedef struct {
1339    ffrt_function_header_t header;
1340    ffrt_function_t func;
1341    ffrt_function_t after_func;
1342    void* arg;
1343} c_function;
1344
1345static void ffrt_exec_function_wrapper(void* t)
1346{
1347    c_function* f = (c_function*)t;
1348    if (f->func) {
1349        f->func(f->arg);
1350    }
1351}
1352
1353static void ffrt_destroy_function_wrapper(void* t)
1354{
1355    c_function* f = (c_function*)t;
1356    if (f->after_func) {
1357        f->after_func(f->arg);
1358    }
1359}
1360
1361#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
1362static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
1363    const ffrt_function_t after_func, void* arg)
1364{
1365    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
1366        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
1367    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
1368    f->header.exec = ffrt_exec_function_wrapper;
1369    f->header.destroy = ffrt_destroy_function_wrapper;
1370    f->func = func;
1371    f->after_func = after_func;
1372    f->arg = arg;
1373    return (ffrt_function_header_t*)f;
1374}
1375
1376static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
1377    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
1378{
1379    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
1380}
1381
1382void ffrt_mutex_task(void *)
1383{
1384    int sum = 0;
1385    ffrt_mutex_t mtx;
1386    tuple t = {&sum, &mtx};
1387    int ret = ffrt_mutex_init(&mtx, NULL);
1388    if (ret != ffrt_success) {
1389        printf("error\n");
1390    }
1391    for (int i = 0; i < 10; i++) {
1392        ffrt_submit_c(func, NULL, &t, NULL, NULL, NULL);
1393    }
1394    ffrt_mutex_destroy(&mtx);
1395    ffrt_wait();
1396    printf("sum = %d\n", sum);
1397}
1398
1399int main(int narg, char** argv)
1400{
1401    int r;
1402    ffrt_submit_c(ffrt_mutex_task, NULL, NULL, NULL, NULL, NULL);
1403    ffrt_wait();
1404    return 0;
1405}
1406```
1407
1408Expected output
1409
1410```
1411sum=10
1412```
1413
1414This example is for reference only and is not encouraged in practice.
1415
1416
1417#### ffrt_cond_t
1418
1419Provides performance implementation similar to pthread semaphore.
1420
1421##### Declaration
1422
1423```{.c}
1424typedef enum {
1425    ffrt_error = -1,
1426    ffrt_success = 0,
1427    ffrt_error_nomem = ENOMEM,
1428    ffrt_error_timedout = ETIMEDOUT,
1429    ffrt_error_busy = EBUSY,
1430    ffrt_error_inval = EINVAL
1431} ffrt_error_t;
1432
1433struct ffrt_cond_t;
1434
1435int ffrt_cond_init(ffrt_cond_t* cond, const ffrt_condattr_t* attr);
1436int ffrt_cond_signal(ffrt_cond_t* cond);
1437int ffrt_cond_broadcast(ffrt_cond_t* cond);
1438int ffrt_cond_wait(ffrt_cond_t*cond, ffrt_mutex_t* mutex);
1439int ffrt_cond_timedwait(ffrt_cond_t* cond, ffrt_mutex_t* mutex, const struct timespec* time_point);
1440int ffrt_cond_destroy(ffrt_cond_t* cond);
1441```
1442
1443##### Parameters
1444
1445`cond`
1446
1447Pointer to the target semaphore.
1448
1449`attr`
1450
1451Pointer to the attribute. A null pointer indicates that the default attribute is used.
1452
1453`mutex`
1454
1455Pointer to the target mutex.
1456
1457`time_point`
1458
1459Pointer to the maximum duration during which the thread is blocked.
1460
1461
1462##### Return value
1463
1464Returns **ffrt_success** if the API is successfully called; returns **ffrt_error_timedout** if the maximum duration is reached before the mutex is locked.
1465
1466##### Description
1467* This API can be called only inside an FFRT task. If it is called outside an FFRT task, undefined behavior may occur.
1468* 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.
1469* **ffrt_cond_t** in the C code must be explicitly created and destroyed by calling **ffrt_cond_init** and **ffrt_cond_destroy**, respectively.
1470* 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.
1471* If **ffrt_cond_t** is accessed after **ffrt_cond_destroy** is called, undefined behavior may occur.
1472
1473##### Example
1474
1475```{.c}
1476#include <stdio.h>
1477#include "ffrt.h"
1478
1479typedef struct {
1480    ffrt_cond_t* cond;
1481    int* a;
1482    ffrt_mutex_t* lock_;
1483} tuple;
1484
1485void func1(void* arg)
1486{
1487    tuple* t = (tuple*)arg;
1488    int ret = ffrt_mutex_lock(t->lock_);
1489    if (ret != ffrt_success) {
1490        printf("error\n");
1491    }
1492    while (*t->a != 1) {
1493        ret = ffrt_cond_wait(t->cond, t->lock_);
1494        if (ret != ffrt_success) {
1495            printf("error\n");
1496        }
1497    }
1498    ret = ffrt_mutex_unlock(t->lock_);
1499    if (ret != ffrt_success) {
1500        printf("error\n");
1501    }
1502    printf("a = %d\n", *(t->a));
1503}
1504
1505void func2(void* arg)
1506{
1507    tuple* t = (tuple*)arg;
1508    int ret = ffrt_mutex_lock(t->lock_);
1509    if (ret != ffrt_success) {
1510        printf("error\n");
1511    }
1512    *(t->a) = 1;
1513    ret = ffrt_cond_signal(t->cond);
1514    if (ret != ffrt_success) {
1515        printf("error\n");
1516    }
1517    ret = ffrt_mutex_unlock(t->lock_);
1518    if (ret != ffrt_success) {
1519        printf("error\n");
1520    }
1521}
1522
1523typedef struct {
1524    ffrt_function_header_t header;
1525    ffrt_function_t func;
1526    ffrt_function_t after_func;
1527    void* arg;
1528} c_function;
1529
1530static void ffrt_exec_function_wrapper(void* t)
1531{
1532    c_function* f = (c_function*)t;
1533    if (f->func) {
1534        f->func(f->arg);
1535    }
1536}
1537
1538static void ffrt_destroy_function_wrapper(void* t)
1539{
1540    c_function* f = (c_function*)t;
1541    if (f->after_func) {
1542        f->after_func(f->arg);
1543    }
1544}
1545
1546#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
1547static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
1548    const ffrt_function_t after_func, void* arg)
1549{
1550    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
1551        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
1552    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
1553    f->header.exec = ffrt_exec_function_wrapper;
1554    f->header.destroy = ffrt_destroy_function_wrapper;
1555    f->func = func;
1556    f->after_func = after_func;
1557    f->arg = arg;
1558    return (ffrt_function_header_t*)f;
1559}
1560
1561static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
1562    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
1563{
1564    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
1565}
1566
1567void ffrt_cv_task(void *)
1568{
1569    ffrt_cond_t cond;
1570    int ret = ffrt_cond_init(&cond, NULL);
1571    if (ret != ffrt_success) {
1572        printf("error\n");
1573    }
1574    int a = 0;
1575    ffrt_mutex_t lock_;
1576    tuple t = {&cond, &a, &lock_};
1577    ret = ffrt_mutex_init(&lock_, NULL);
1578    if (ret != ffrt_success) {
1579        printf("error\n");
1580    }
1581    ffrt_submit_c(func1, NULL, &t, NULL, NULL, NULL);
1582    ffrt_submit_c(func2, NULL, &t, NULL, NULL, NULL);
1583    ffrt_wait();
1584    ffrt_cond_destroy(&cond);
1585    ffrt_mutex_destroy(&lock_);
1586}
1587
1588int main(int narg, char** argv)
1589{
1590    ffrt_submit_c(ffrt_cv_task, NULL, NULL, NULL, NULL, NULL);
1591    ffrt_wait();
1592    return 0;
1593}
1594```
1595
1596Expected output
1597
1598```
1599a=1
1600```
1601
1602This example is for reference only and is not encouraged in practice.
1603
1604#### ffrt_usleep
1605
1606Provides performance implementation similar to C11 sleep and Linux usleep.
1607
1608##### Declaration
1609
1610```{.c}
1611int ffrt_usleep(uint64_t usec);
1612```
1613
1614##### Parameters
1615
1616`usec`
1617
1618Duration that the calling thread is suspended, in μs.
1619
1620##### Return value
1621
1622N/A
1623
1624##### Description
1625* This API can be called only inside an FFRT task. If it is called outside an FFRT task, undefined behavior may occur.
1626* The traditional function **sleep** may cause unexpected kernel mode trap. **ffrt_usleep** solves this problem and therefore provides better performance if used properly.
1627
1628##### Example
1629
1630```{.c}
1631#include <time.h>
1632#include <stdio.h>
1633#include "ffrt.h"
1634
1635void func(void* arg)
1636{
1637    time_t current_time = time(NULL);
1638    printf("Time: %s", ctime(&current_time));
1639    ffrt_usleep(2000000); // Suspend for 2 seconds
1640    current_time = time(NULL);
1641    printf("Time: %s", ctime(&current_time));
1642}
1643
1644typedef struct {
1645    ffrt_function_header_t header;
1646    ffrt_function_t func;
1647    ffrt_function_t after_func;
1648    void* arg;
1649} c_function;
1650
1651static void ffrt_exec_function_wrapper(void* t)
1652{
1653    c_function* f = (c_function*)t;
1654    if (f->func) {
1655        f->func(f->arg);
1656    }
1657}
1658
1659static void ffrt_destroy_function_wrapper(void* t)
1660{
1661    c_function* f = (c_function*)t;
1662    if (f->after_func) {
1663        f->after_func(f->arg);
1664    }
1665}
1666
1667#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
1668static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
1669    const ffrt_function_t after_func, void* arg)
1670{
1671    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
1672        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
1673    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
1674    f->header.exec = ffrt_exec_function_wrapper;
1675    f->header.destroy = ffrt_destroy_function_wrapper;
1676    f->func = func;
1677    f->after_func = after_func;
1678    f->arg = arg;
1679    return (ffrt_function_header_t*)f;
1680}
1681
1682static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
1683    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
1684{
1685    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
1686}
1687
1688int main(int narg, char** argv)
1689{
1690    ffrt_submit_c(func, NULL, NULL, NULL, NULL, NULL);
1691    ffrt_wait();
1692    return 0;
1693}
1694```
1695
1696An output case is as follows:
1697
1698```
1699Time: Tue Aug 13 15:45:30 2024
1700Time: Tue Aug 13 15:45:32 2024
1701```
1702
1703#### ffrt_yield
1704
1705Passes control to other tasks so that they can be executed. If there is no other task that can be executed, this API is invalid.
1706
1707##### Declaration
1708
1709```{.c}
1710void ffrt_yield();
1711```
1712
1713##### Parameters
1714
1715N/A
1716
1717##### Return value
1718
1719N/A
1720
1721##### Description
1722* This API can be called only inside an FFRT task. If it is called outside an FFRT task, undefined behavior may occur.
1723* The exact behavior of this API depends on the implementation, especially the mechanism and system state of the FFRT scheduler in use.
1724
1725##### Example
1726
1727N/A
1728
1729### ffrt timer
1730
1731FFRT supports the capability of starting and stopping the timer.
1732
1733#### ffrt_timer_start
1734
1735Starts a timer.
1736
1737##### Declaration
1738```{.c}
1739typedef int ffrt_timer_t;
1740typedef void (*ffrt_timer_cb)(void* data);
1741
1742ffrt_timer_t ffrt_timer_start(ffrt_qos_t qos, uint64_t timeout, void* data, ffrt_timer_cb cb, bool repeat);
1743```
1744
1745##### Parameters
1746
1747`qos`
1748
1749QoS.
1750
1751`timeout`
1752
1753Timeout of the timer.
1754
1755`data`
1756
1757Pointer to the input parameter in the callback function invoked upon a timeout.
1758
1759`cb`
1760
1761Callback function invoked upon a timeout.
1762
1763`repeat`
1764
1765Whether to repeat the timer.
1766
1767##### Return value
1768
1769Handle to the timer.
1770
1771##### Description
1772N/A
1773
1774##### Example
1775```{.c}
1776#include <stdint.h>
1777#include <unistd.h>
1778#include "ffrt.h"
1779
1780static void testfun(void *data)
1781{
1782    *(int *)data += 1;
1783}
1784
1785void (*cb)(void *) = testfun;
1786
1787int main(int narg, char** argv)
1788{
1789    static int x = 0;
1790    int *xf = &x;
1791    void *data = xf;
1792    uint64_t timeout = 200;
1793    int handle = ffrt_timer_start(ffrt_qos_default, timeout, data, cb, false);
1794    usleep(300000);
1795    ffrt_timer_stop(ffrt_qos_default, handle);
1796    printf("data: %d\n", x);
1797    return 0;
1798}
1799```
1800
1801Expected output
1802
1803```
1804data: 1
1805```
1806
1807#### ffrt_timer_stop
1808
1809Stops the timer.
1810
1811##### Declaration
1812```{.c}
1813int ffrt_timer_stop(ffrt_qos_t qos, ffrt_timer_t handle);
1814```
1815
1816##### Parameters
1817
1818`qos`
1819
1820QoS.
1821
1822`handle`
1823
1824Handle to the timer.
1825
1826##### Return value
1827
1828**0** if the call is successful; **-1** if the call fails.
1829
1830##### Description
1831N/A
1832
1833##### Example
1834```{.c}
1835#include <stdint.h>
1836#include <unistd.h>
1837#include "ffrt.h"
1838
1839static void testfun(void *data)
1840{
1841    *(int *)data += 1;
1842}
1843
1844void (*cb)(void *) = testfun;
1845
1846int main(int narg, char** argv)
1847{
1848    static int x = 0;
1849    int *xf = &x;
1850    void *data = xf;
1851    uint64_t timeout = 200;
1852    int handle = ffrt_timer_start(ffrt_qos_default, timeout, data, cb, false);
1853    usleep(300000);
1854    ffrt_timer_stop(ffrt_qos_default, handle);
1855    printf("data: %d\n", x);
1856    return 0;
1857}
1858```
1859
1860Expected output
1861
1862```
1863data: 1
1864```
1865
1866### ffrt looper
1867
1868FFRT provides the looper mechanism. The looper supports task submission, event listening, and timer. The looper runs in the user thread.
1869
1870#### ffrt_loop_create
1871
1872Creates a loop.
1873
1874##### Declaration
1875```{.c}
1876typedef void* ffrt_loop_t;
1877
1878ffrt_loop_t ffrt_loop_create(ffrt_queue_t queue);
1879```
1880
1881##### Parameters
1882
1883`queue`
1884
1885Queue, which must be a concurrent queue.
1886
1887##### Return value
1888
1889Loop object.
1890
1891##### Description
1892N/A
1893
1894##### Example
1895```{.c}
1896#include <stdint.h>
1897#include <unistd.h>
1898#include <stdio.h>
1899#include "c/loop.h"
1900
1901int main(int narg, char** argv)
1902{
1903    ffrt_queue_attr_t queue_attr;
1904    (void)ffrt_queue_attr_init(&queue_attr);
1905    ffrt_queue_t queue_handle = ffrt_queue_create(ffrt_queue_concurrent, "test_queue", &queue_attr);
1906
1907    auto loop = ffrt_loop_create(queue_handle);
1908
1909    if (loop != NULL) {
1910        printf("loop is not null.\n");
1911    }
1912
1913    int ret = ffrt_loop_destroy(loop);
1914
1915    ffrt_queue_attr_destroy(&queue_attr);
1916    ffrt_queue_destroy(queue_handle);
1917    return 0;
1918}
1919```
1920
1921Expected output
1922
1923```
1924loop is not null.
1925```
1926
1927#### ffrt_loop_destroy
1928
1929Destroys a loop.
1930
1931##### Declaration
1932```{.c}
1933int ffrt_loop_destroy(ffrt_loop_t loop);
1934```
1935
1936##### Parameters
1937
1938`loop`
1939
1940Loop object.
1941
1942##### Return value
1943
1944**0** if the call is successful; **-1** if the call fails.
1945
1946##### Description
1947N/A
1948
1949##### Example
1950```{.c}
1951#include <stdint.h>
1952#include <unistd.h>
1953#include <stdio.h>
1954#include "c/loop.h"
1955
1956int main(int narg, char** argv)
1957{
1958    ffrt_queue_attr_t queue_attr;
1959    (void)ffrt_queue_attr_init(&queue_attr);
1960    ffrt_queue_t queue_handle = ffrt_queue_create(ffrt_queue_concurrent, "test_queue", &queue_attr);
1961
1962    auto loop = ffrt_loop_create(queue_handle);
1963
1964    int ret = ffrt_loop_destroy(loop);
1965
1966    if (ret == 0) {
1967        printf("loop normal destruction.");
1968    }
1969
1970    ffrt_queue_attr_destroy(&queue_attr);
1971    ffrt_queue_destroy(queue_handle);
1972    return 0;
1973}
1974```
1975
1976Expected output
1977
1978```
1979loop normal destruction.
1980```
1981
1982#### ffrt_loop_run
1983
1984Runs a loop.
1985
1986##### Declaration
1987```{.c}
1988int ffrt_loop_run(ffrt_loop_t loop);
1989```
1990
1991##### Parameters
1992
1993`loop`
1994
1995Loop object.
1996
1997##### Return value
1998
1999**0** if the call is successful; **-1** if the call fails.
2000
2001##### Description
2002N/A
2003
2004##### Example
2005```{.c}
2006#include <pthread.h>
2007#include <unistd.h>
2008#include <stdio.h>
2009#include "c/loop.h"
2010
2011void* ThreadFunc(void* p)
2012{
2013    int ret = ffrt_loop_run(p);
2014    if (ret == 0) {
2015        printf("loop normal operation.");
2016    }
2017    return nullptr;
2018}
2019int main(int narg, char** argv)
2020{
2021    ffrt_queue_attr_t queue_attr;
2022    (void)ffrt_queue_attr_init(&queue_attr);
2023    ffrt_queue_t queue_handle = ffrt_queue_create(ffrt_queue_concurrent, "test_queue", &queue_attr);
2024
2025    auto loop = ffrt_loop_create(queue_handle);
2026    pthread_t thread;
2027    pthread_create(&thread, 0, ThreadFunc, loop);
2028
2029    ffrt_loop_stop(loop);
2030    int ret = ffrt_loop_destroy(loop);
2031
2032    ffrt_queue_attr_destroy(&queue_attr);
2033    ffrt_queue_destroy(queue_handle);
2034    return 0;
2035}
2036```
2037
2038Expected output
2039
2040```
2041loop normal operation.
2042```
2043
2044#### ffrt_loop_stop
2045
2046Stops a loop.
2047
2048##### Declaration
2049```{.c}
2050void ffrt_loop_stop(ffrt_loop_t loop);
2051```
2052
2053##### Parameters
2054
2055`loop`
2056
2057Loop object.
2058
2059##### Return value
2060
2061N/A.
2062
2063##### Description
2064N/A
2065
2066##### Example
2067```{.c}
2068#include <pthread.h>
2069#include <unistd.h>
2070#include <stdio.h>
2071#include "c/loop.h"
2072
2073void* ThreadFunc(void* p)
2074{
2075    int ret = ffrt_loop_run(p);
2076    return nullptr;
2077}
2078int main(int narg, char** argv)
2079{
2080    ffrt_queue_attr_t queue_attr;
2081    (void)ffrt_queue_attr_init(&queue_attr);
2082    ffrt_queue_t queue_handle = ffrt_queue_create(ffrt_queue_concurrent, "test_queue", &queue_attr);
2083
2084    auto loop = ffrt_loop_create(queue_handle);
2085    pthread_t thread;
2086    pthread_create(&thread, 0, ThreadFunc, loop);
2087
2088    ffrt_loop_stop(loop);
2089    int ret = ffrt_loop_destroy(loop);
2090
2091    ffrt_queue_attr_destroy(&queue_attr);
2092    ffrt_queue_destroy(queue_handle);
2093    return 0;
2094}
2095```
2096
2097Expected output
2098
2099```
2100**0** if the loop object is stopped normally.
2101```
2102
2103#### ffrt_loop_epoll_ctl
2104
2105Manages listening events on a loop.
2106
2107##### Declaration
2108```{.c}
2109int ffrt_loop_epoll_ctl(ffrt_loop_t loop, int op, int fd, uint32_t events, void *data, ffrt_poller_cb cb);
2110```
2111
2112##### Parameters
2113
2114`loop`
2115
2116Loop object.
2117
2118`op`
2119
2120Operation to be performed, such as **EPOLL_CTL_ADD** and **EPOLL_CLT_DEL**.
2121
2122`fd`
2123
2124File descriptor.
2125
2126`events`
2127
2128Events linked to the file descriptor.
2129
2130`data`
2131
2132Pointer to the input parameter in the callback function invoked upon event changes.
2133
2134`cb`
2135
2136Callback function invoked upon event changes.
2137
2138##### Return value
2139
2140**0** if the call is successful; **-1** if the call fails.
2141
2142##### Description
2143N/A
2144
2145##### Example
2146```{.c}
2147#include <pthread.h>
2148#include <unistd.h>
2149#include <stdio.h>
2150#include <functional>
2151#include <sys/epoll.h>
2152#include <sys/eventfd.h>
2153#include "c/loop.h"
2154#include "ffrt.h"
2155
2156void* ThreadFunc(void* p)
2157{
2158    int ret = ffrt_loop_run(p);
2159    return nullptr;
2160}
2161
2162static void testfun(void* data)
2163{
2164    *(int*)data += 1;
2165}
2166
2167static void (*cb)(void*) = testfun;
2168
2169void testCallBack(void *data, unsigned int events) {}
2170
2171struct TestData {
2172    int fd;
2173    uint64_t expected;
2174};
2175
2176int main(int narg, char** argv)
2177{
2178    ffrt_queue_attr_t queue_attr;
2179    (void)ffrt_queue_attr_init(&queue_attr);
2180    ffrt_queue_t queue_handle = ffrt_queue_create(ffrt_queue_concurrent, "test_queue", &queue_attr);
2181
2182    auto loop = ffrt_loop_create(queue_handle);
2183    int result1 = 0;
2184    std::function<void()> &&basicFunc1 = [&result1]() {result1 += 10;};
2185    ffrt_task_handle_t task1 = ffrt_queue_submit_h(queue_handle, ffrt::create_function_wrapper(basicFunc1, ffrt_function_kind_queue), nullptr);
2186
2187    pthread_t thread;
2188    pthread_create(&thread, 0, ThreadFunc, loop);
2189
2190    static int x = 0;
2191    int* xf = &x;
2192    void* data = xf;
2193    uint64_t timeout1 = 20;
2194    uint64_t timeout2 = 10;
2195    uint64_t expected = 0xabacadae;
2196
2197    int testFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
2198    struct TestData testData {.fd = testFd, .expected = expected};
2199    ffrt_timer_t timeHandle = ffrt_loop_timer_start(loop, timeout1, data, cb, false);
2200
2201    int ret = ffrt_loop_epoll_ctl(loop, EPOLL_CTL_ADD, testFd, EPOLLIN, (void*)(&testData), testCallBack);
2202    if (ret == 0) {
2203        printf("ffrt_loop_epoll_ctl executed successfully.\n");
2204    }
2205    ssize_t n = write(testFd, &expected, sizeof(uint64_t));
2206    usleep(25000);
2207    ffrt_loop_epoll_ctl(loop, EPOLL_CTL_DEL, testFd, 0, nullptr, nullptr);
2208
2209    ffrt_loop_stop(loop);
2210    pthread_join(thread, nullptr);
2211    ffrt_loop_timer_stop(loop, timeHandle);
2212    ret = ffrt_loop_destroy(loop);
2213
2214    ffrt_queue_attr_destroy(&queue_attr);
2215    ffrt_queue_destroy(queue_handle);
2216    return 0;
2217}
2218```
2219
2220Expected output
2221
2222```
2223ffrt_loop_epoll_ctl if the operation is successful.
2224```
2225
2226#### ffrt_loop_timer_start
2227
2228Starts the timer on a loop.
2229
2230##### Declaration
2231```{.c}
2232ffrt_timer_t ffrt_loop_timer_start(ffrt_loop_t loop, uint64_t timeout, void* data, ffrt_timer_cb cb, bool repeat);
2233```
2234
2235##### Parameters
2236
2237`loop`
2238
2239Loop object.
2240
2241`timeout`
2242
2243Timeout of the timer.
2244
2245`data`
2246
2247Pointer to the input parameter in the callback function invoked upon event changes.
2248
2249`cb`
2250
2251Callback function invoked upon event changes.
2252
2253`repeat`
2254
2255* Whether to repeat the timer.
2256
2257##### Return value
2258
2259Handle to the timer.
2260
2261##### Description
2262N/A
2263
2264##### Example
2265For details, see the **ffrt_loop_epoll_ctl** interface example.
2266
2267#### ffrt_loop_timer_stop
2268
2269Stops the timer.
2270
2271##### Declaration
2272```{.c}
2273int ffrt_loop_timer_stop(ffrt_loop_t loop, ffrt_timer_t handle)
2274```
2275
2276##### Parameters
2277
2278`loop`
2279
2280Loop object.
2281
2282`handle`
2283
2284Handle to the timer.
2285
2286##### Return value
2287
2288**0** if the call is successful; **-1** if the call fails.
2289
2290##### Description
2291N/A
2292
2293##### Example
2294For details, see the **ffrt_loop_epoll_ctl** interface example.
2295
2296## Long-Time Task Monitoring
2297
2298### Mechanism
2299* When the task execution reaches one second, stack printing is triggered. The stack printing interval is then changed to one minute. After 10 prints, the interval is changed to 10 minutes. After another 10 prints, the interval is changed to and fixed at 30 minutes.
2300* The **GetBacktraceStringByTid** interface of the DFX is called for the stack printing. This interface sends stack capture signals to the blocked thread to trigger interrupts and capture the call stack return.
2301
2302### Example
2303Search for the keyword **RecordSymbolAndBacktrace** in the corresponding process log. The following is an example of the corresponding log:
2304
2305```
2306W C01719/ffrt: 60500:RecordSymbolAndBacktrace:159 Tid[16579] function occupies worker for more than [1]s.
2307W C01719/ffrt: 60501:RecordSymbolAndBacktrace:164 Backtrace:
2308W C01719/ffrt: #00 pc 00000000000075f0 /system/lib64/module/file/libhash.z.so
2309W C01719/ffrt: #01 pc 0000000000008758 /system/lib64/module/file/libhash.z.so
2310W C01719/ffrt: #02 pc 0000000000012b98 /system/lib64/module/file/libhash.z.so
2311W C01719/ffrt: #03 pc 000000000002aaa0 /system/lib64/platformsdk/libfilemgmt_libn.z.so
2312W C01719/ffrt: #04 pc 0000000000054b2c /system/lib64/platformsdk/libace_napi.z.so
2313W C01719/ffrt: #05 pc 00000000000133a8 /system/lib64/platformsdk/libuv.so
2314W C01719/ffrt: #06 pc 00000000000461a0 /system/lib64/chipset-sdk/libffrt.so
2315W C01719/ffrt: #07 pc 0000000000046d44 /system/lib64/chipset-sdk/libffrt.so
2316W C01719/ffrt: #08 pc 0000000000046a6c /system/lib64/chipset-sdk/libffrt.so
2317W C01719/ffrt: #09 pc 00000000000467b0 /system/lib64/chipset-sdk/libffrt.so
2318```
2319The log prints the task stack, Worker thread ID, and execution time of the long-time task. Find the corresponding component based on the stack to determine the blocking cause.
2320
2321
2322### Precautions
2323During long-time task monitoring, an interrupt signal is sent. If your code contains **sleep** or a blocked thread that will be woken up by the interrupt, you should receive the return value of the blocked thread and call the code again.
2324The following is an example:
2325```
2326unsigned int leftTime = sleep(10);
2327while (leftTime != 0) {
2328    leftTime = sleep(leftTime);
2329}
2330```
2331
2332## How to Develop
2333
2334The following describes how to use the native APIs provided by FFRT to create parallel tasks and serial queue tasks and destroy corresponding resources.
2335
2336**Adding Dynamic Link Libraries**
2337
2338Add the following libraries to **CMakeLists.txt**.
2339```txt
2340libffrt.z.so
2341```
2342
2343**Including Header Files**
2344```c++
2345#include "ffrt/task.h"
2346#include "ffrt/type_def.h"
2347#include "ffrt/condition_variable.h"
2348#include "ffrt/mutex.h"
2349#include "ffrt/queue.h"
2350#include "ffrt/sleep.h"
2351```
2352
23531. **Encapsulate the function to be executed.**
2354    ```c++
2355    // Method 1: Use the template. C++ is supported.
2356    template<class T>
2357    struct Function {
2358        ffrt_function_header_t header;
2359        T closure;
2360    };
2361
2362    template<class T>
2363    void ExecFunctionWrapper(void* t)
2364    {
2365        auto f = reinterpret_cast<Function<std::decay_t<T>>*>(t);
2366        f->closure();
2367    }
2368
2369    template<class T>
2370    void DestroyFunctionWrapper(void* t)
2371    {
2372        auto f = reinterpret_cast<Function<std::decay_t<T>>*>(t);
2373        f->closure = nullptr;
2374    }
2375
2376    template<class T>
2377    static inline ffrt_function_header_t* create_function_wrapper(T&& func,
2378        ffrt_function_kind_t kind = ffrt_function_kind_general)
2379    {
2380        using function_type = Function<std::decay_t<T>>;
2381        auto p = ffrt_alloc_auto_managed_function_storage_base(kind);
2382        auto f = new (p)function_type;
2383        f->header.exec = ExecFunctionWrapper<T>;
2384        f->header.destroy = DestroyFunctionWrapper<T>;
2385        f->closure = std::forward<T>(func);
2386        return reinterpret_cast<ffrt_function_header_t*>(f);
2387    }
2388
2389    // Method 2
2390    typedef struct {
2391        ffrt_function_header_t header;
2392        ffrt_function_t func;
2393        ffrt_function_t after_func;
2394        void* arg;
2395    } CFunction;
2396
2397    static void FfrtExecFunctionWrapper(void* t)
2398    {
2399        CFunction* f = static_cast<CFunction*>(t);
2400        if (f->func) {
2401            f->func(f->arg);
2402        }
2403    }
2404
2405    static void FfrtDestroyFunctionWrapper(void* t)
2406    {
2407        CFunction* f = static_cast<CFunction*>(t);
2408        if (f->after_func) {
2409            f->after_func(f->arg);
2410        }
2411    }
2412
2413    #define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
2414    static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
2415        const ffrt_function_t after_func, void* arg, ffrt_function_kind_t kind_t = ffrt_function_kind_general)
2416    {
2417        FFRT_STATIC_ASSERT(sizeof(CFunction) <= ffrt_auto_managed_function_storage_size,
2418            size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
2419        CFunction* f = static_cast<CFunction*>(ffrt_alloc_auto_managed_function_storage_base(kind_t));
2420        f->header.exec = FfrtExecFunctionWrapper;
2421        f->header.destroy = FfrtDestroyFunctionWrapper;
2422        f->func = func;
2423        f->after_func = after_func;
2424        f->arg = arg;
2425        return reinterpret_cast<ffrt_function_header_t*>(f);
2426    }
2427
2428    // Example: function to be submitted for execution.
2429    void OnePlusForTest(void* arg)
2430    {
2431        (*static_cast<int*>(arg)) += 1;
2432    }
2433    ```
2434
24352. **Set the task attributes.**
2436
2437    Set the task attributes, including the QoS and task name, before submitting the task.
2438    ```c++
2439    // ******Initialize the attributes of the parallel task******
2440    ffrt_task_attr_t attr;
2441    ffrt_task_attr_init(&attr);
2442
2443    // ******Create a serial queue******
2444
2445    // Create the attributes of the serial queue.
2446    ffrt_queue_attr_t queue_attr;
2447    // Create the handle of the serial queue.
2448    ffrt_queue_t queue_handle;
2449
2450    // Initialize the queue attribute.
2451    (void)ffrt_queue_attr_init(&queue_attr);
2452
2453    // Set the QoS if necessary.
2454    ffrt_queue_attr_set_qos(&queue_attr, static_cast<ffrt_qos_t>(ffrt_qos_inherit));
2455    // Set the timeout period (ms) if necessary.
2456    ffrt_queue_attr_set_timeout(&queue_attr, 10000);
2457    // Set the timeout callback if necessary.
2458    int x = 0;
2459    ffrt_queue_attr_set_callback(&queue_attr, ffrt_create_function_wrapper(OnePlusForTest, NULL, &x,
2460        ffrt_function_kind_queue));
2461
2462    // Initialize the queue based on the attributes.
2463    queue_handle = ffrt_queue_create(ffrt_queue_serial, "test_queue", &queue_attr);
2464    ```
2465
24663. **Submit the task.**
2467    ```c++
2468    int a = 0;
2469    // ******Parallel task******
2470    // Submit the parallel task without obtaining a handle.
2471    ffrt_submit_base(ffrt_create_function_wrapper(OnePlusForTest, NULL, &a), NULL, NULL, &attr);
2472    // Submit the parallel task and obtain a handle.
2473    ffrt_task_handle_t task = ffrt_submit_h_base(
2474        ffrt_create_function_wrapper(OnePlusForTest, NULL, &a), NULL, NULL, &attr);
2475
2476    // ******Serial queue task******
2477    // Submit the serial queue task without obtaining a handle.
2478    ffrt_queue_submit(queue_handle, ffrt_create_function_wrapper(OnePlusForTest, nullptr, &a,
2479        ffrt_function_kind_queue), nullptr);
2480    // Submit the serial queue task and obtain a handle.
2481    ffrt_task_handle_t handle = ffrt_queue_submit_h(queue_handle,
2482        ffrt_create_function_wrapper(OnePlusForTest, nullptr, &a, ffrt_function_kind_queue), nullptr);
2483
2484    // Call wait if you need to wait for the execution result.
2485    const std::vector<ffrt_dependence_t> wait_deps = {{ffrt_dependence_task, task}};
2486    ffrt_deps_t wait{static_cast<uint32_t>(wait_deps.size()), wait_deps.data()};
2487    ffrt_wait_deps(&wait);
2488
2489    ffrt_queue_wait(handle);
2490    ```
2491
24924. **Destroy the resources after the task is submitted.**
2493    ```c++
2494    // ******Destroy the parallel task******
2495    ffrt_task_attr_destroy(&attr);
2496    ffrt_task_handle_destroy(task);
2497
2498    // ******Destroy the serial queue task******
2499    // Destroy the task handle and then the queue.
2500    ffrt_queue_attr_destroy(&queue_attr);
2501    ffrt_task_handle_destroy(handle);
2502    ffrt_queue_destroy(queue_handle);
2503    ```
2504
2505## Suggestions
2506
2507### Suggestion 1: Functional programming
2508
2509Basic idea: Use functional programming for the calculation process.
2510
2511* Use pure functions and encapsulate them to express each step of the process.
2512* There is no global data access.
2513* There is no internal state reserved.
2514* Use **ffrt_submit_base()** to submit a function in asynchronous mode for execution.
2515* 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.
2516* Use **inDeps** and **outDeps** to specify the dependency between tasks to ensure the correctness of program execution.
2517
2518> **NOTE**
2519>
2520> Using pure functions helps you maximize the parallelism and avoid data races and lock abuse.
2521
2522In practice, you may not use pure functions in certain scenarios, with the following prerequisites:
2523
2524* **in_deps** and **out_deps** can ensure the correctness of program execution.
2525* The lock mechanism provided by FFRT is used to protect access to global variables.
2526
2527
2528### Suggestion 2: Use FFRT APIs
2529
2530* 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.
2531* Use the lock, condition variable, sleep, and I/O APIs provided by FFRT to replace the APIs of the system thread library.
2532* Using the APIs of the system thread library may block worker threads and result in extra performance overhead.
2533
2534### Suggestion 3: Deadline mechanism
2535
2536* Use FFRT APIs in processing flows that feature periodic/repeated execution.
2537* Use FFRT APIs in processing flows with clear time constraints and is performance critical.
2538* Use FFRT APIs in relatively large-granularity processing flows, such as the frame processing flow with the 16.6 ms time constraint.
2539
2540### Suggestion 4: Migration from the thread model
2541
2542* Create a thread instead of creating an FFRT task.
2543* A thread is logically similar to a task without **in_deps**.
2544* Identify the dependency between threads and express the dependencies in **in_deps** or **out_deps** of the task.
2545* Decompose an intra-thread computing process into asynchronous tasks for invoking.
2546* Use the task dependency and lock mechanism to avoid data races of concurrent tasks.
2547
2548### Suggestion 5: C++ APIs recommended
2549
2550* The FFRT C++ APIs are implemented based on the C APIs. Before using the APIs, you can manually add the C++ header file.
2551* For details about how to download C++ APIs, see [FFRT C++ APIs](https://gitee.com/openharmony/resourceschedule_ffrt/tree/master/interfaces/kits).
2552
2553## Constraints
2554
2555
2556After an FFRT object is initialized in the C code, you are responsible for setting the object to null or destroying the object.
2557
2558To 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.
2559
2560Noncompliant example 1: Repeated calling of **destroy()** may cause unpredictable data damage.
2561
2562```{.c}
2563#include "ffrt.h"
2564void abnormal_case_1()
2565{
2566    ffrt_task_handle_t h = ffrt_submit_h_base([](){printf("Test task running...\n");}, NULL, NULL, NULL, NULL, NULL);
2567    ...
2568    ffrt_task_handle_destroy(h);
2569    ffrt_task_handle_destroy(h); // double free
2570}
2571```
2572
2573Noncompliant example 2: A memory leak occurs if **destroy()** is not called.
2574
2575```{.c}
2576#include "ffrt.h"
2577void abnormal_case_2()
2578{
2579    ffrt_task_handle_t h = ffrt_submit_h_base([](){printf("Test task running...\n");}, NULL, NULL, NULL, NULL, NULL);
2580    ...
2581    // Memory leak
2582}
2583```
2584
2585Recommended example: Call **destroy()** only once; set the object to null if necessary.
2586
2587```{.c}
2588#include "ffrt.h"
2589void normal_case()
2590{
2591    ffrt_task_handle_t h = ffrt_submit_h_base([](){printf("Test task running...\n");}, NULL, NULL, NULL, NULL, NULL);
2592    ...
2593    ffrt_task_handle_destroy(h);
2594    h = nullptr; // if necessary
2595}
2596```
2597