• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Function Flow Runtime Development
2
3<!--Kit: Function Flow Runtime Kit-->
4<!--Subsystem: Resourceschedule-->
5<!--Owner: @chuchihtung; @yanleo-->
6<!--Designer: @geoffrey_guo; @huangyouzhong-->
7<!--Tester: @lotsof; @sunxuhao-->
8<!--Adviser: @foryourself-->
9
10## Overview
11
12Function Flow Runtime (FFRT) is a task-based and data-driven concurrent programming model that allows you to develop an application by creating tasks and describing their dependencies.
13Specifically, 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.
14
15This document provides guidance for you to implement concurrent programming based on the FFRT programming model.
16
17## Maintenance and Test
18
19### Timeout Monitoring
20
21FFRT provides a queue-level and task-level timeout maintenance and test mechanism to monitor the end-to-end time for scheduling queues and tasks that carry important responsibilities in user services.
22
23- When a task in the queue times out, the FFRT prints alarm logs and notifies the service through the callback.
24- When a task times out, the FFRT prints alarm logs and calls the process-level callback function.
25
26> **NOTE**
27>
28> The callback function executed when a task times out must be unique in the process and should be configured in the FFRT by the service party before the task is submitted. The callback function cannot be configured during task submission or task timeout detection.
29
30The APIs are as follows:
31
32| C++ API                                                                                                                                  | C API                                                                               | Description                  |
33| ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | ---------------------- |
34| [queue_attr::timeout](https://gitee.com/openharmony/resourceschedule_ffrt/blob/master/docs/ffrt-api-guideline-cpp.md#set-queue-timeout)   | [ffrt_queue_attr_set_timeout](ffrt-api-guideline-c.md#ffrt_queue_attr_t)   | Sets the queue timeout.    |
35| [queue_attr::callback](https://gitee.com/openharmony/resourceschedule_ffrt/blob/master/docs/ffrt-api-guideline-cpp.md#set-queue-callback) | [ffrt_queue_attr_set_callback](ffrt-api-guideline-c.md#ffrt_queue_attr_t) | Sets the queue timeout callback.|
36
37### Long-Time Task Monitoring
38
39**Mechanism**
40
41- 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.
42- The `GetBacktraceStringByTid` API of DFX is called for stack printing. This API sends stack capture signals to the blocked thread to trigger interrupts and capture the call stack return.
43
44**Example**
45
46Search for the keyword **RecordSymbolAndBacktrace** in the corresponding process log. The following is an example of the corresponding log:
47
48```txt
49W C01719/ffrt: 60500:RecordSymbolAndBacktrace:159 Tid[16579] function occupies worker for more than [1]s.
50W C01719/ffrt: 60501:RecordSymbolAndBacktrace:164 Backtrace:
51W C01719/ffrt: #00 pc 00000000000075f0 /system/lib64/module/file/libhash.z.so
52W C01719/ffrt: #01 pc 0000000000008758 /system/lib64/module/file/libhash.z.so
53W C01719/ffrt: #02 pc 0000000000012b98 /system/lib64/module/file/libhash.z.so
54W C01719/ffrt: #03 pc 000000000002aaa0 /system/lib64/platformsdk/libfilemgmt_libn.z.so
55W C01719/ffrt: #04 pc 0000000000054b2c /system/lib64/platformsdk/libace_napi.z.so
56W C01719/ffrt: #05 pc 00000000000133a8 /system/lib64/platformsdk/libuv.so
57W C01719/ffrt: #06 pc 00000000000461a0 /system/lib64/chipset-sdk/libffrt.so
58W C01719/ffrt: #07 pc 0000000000046d44 /system/lib64/chipset-sdk/libffrt.so
59W C01719/ffrt: #08 pc 0000000000046a6c /system/lib64/chipset-sdk/libffrt.so
60W C01719/ffrt: #09 pc 00000000000467b0 /system/lib64/chipset-sdk/libffrt.so
61```
62
63The 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.
64
65**Precautions**
66
67N/A
68
69### Running Information Dump
70
71**Mechanism**
72
73FFRT provides an external interface API `ffrt_dump` to dump the internal information about the running of the FFRT subsystem, including:
74
751. FFRT statistics: number of submitted tasks, number of running tasks, number of coroutine switching times, and number of completed tasks;
762. Worker thread information: number of Worker threads in each QoS, Worker ID, ID of the running task, task name, and task type.
773. Common task information: common tasks that are not released in the current process, dump task name and ID, and call stack information of each task.
784. Queue task information: queue tasks that are not released in the current process, dump task name and ID, and call stack information of each task.
79
80When the current process is frozen, the DFX module proactively calls the `ffrt_dump` API to dump the FFRT information to the freeze file and store the file in the `/data/log/faultlog/faultlogger/` directory. You can directly use the task call stack information in the file to locate the frame freezing of the corresponding task.
81
82**Example**
83
84```txt
85ready task ptr: qos 0 readptr 79 writeptr 79
86ready task ptr: qos 1 readptr 360 writeptr 360
87ready task ptr: qos 2 readptr 19 writeptr 19
88ready task ptr: qos 3 readptr 0 writeptr 0
89ready task ptr: qos 4 readptr 0 writeptr 0
90ready task ptr: qos 5 readptr 65 writeptr 65
91ready task ptr: qos 6 readptr 0 writeptr 0
92ready task ptr: qos 7 readptr 0 writeptr 0
93submit queue: readptr 24 writeptr 24
94intr wake: status 255
95proc status: taskCnt 23 vercnt 0sigCnt0
96    |-> worker count
97        qos 0: worker num:1 tid:31676
98        qos 2: worker num:3 tid:51349, 28769, 28565
99        qos 5: worker num:1 tid:30605
100    |-> worker status
101        qos 0: worker tid 31676 is running nothing
102        qos 2: worker tid 51349 is running nothing
103        qos 2: worker tid 28769 is running, task id 24591 name sq_CesSrvMain_12_PublishCommonEventDetailed_24591 fromTid 43928 createTime 2024-11-27 02:52:27.325248 executeTime 2024-11-27 02:52:27.326150
104        qos 2: worker tid 28565 is running, task id 24611 name sq_dfx_freeze_task_queue_16_NotifyAppFaultTask_24611 fromTid 43833 createTime 2024-11-27 02:52:38.114787 executeTime 2024-11-27 02:52:38.115424
105        qos 5: worker tid 30605 is running, task id 24595 name sq_AbilityManagerService_19_SubmitTaskInner_24595 fromTid 43610 createTime 2024-11-27 02:52:27.844237 executeTime 2024-11-27 02:52:27.844573
106    |-> ready queue status
107    |-> blocked by task dependence
108        <1/1>stack: task id 3,qos 2,name AgingTask fromTid 43417 createTime 2024-11-27 01:21:39.641673 executeTime 2024-11-27 01:21:39.642290
109#00 pc 0000000000065c5c /system/lib64/ndk/libffrt.so(CoYield()+560)(22be57f01a789a03813d26a19c3a4042)
110#01 pc 00000000000a3268 /system/lib64/ndk/libffrt.so(ffrt::this_task::SleepUntilImpl(std::__h::chrono::time_point<std::__h::chrono::steady_clock, std::__h::chrono::duration<long long, std::__h::ratio<1l, 1000000000l>>> const&)+356)(22be57f01a789a03813d26a19c3a4042)
111#02 pc 00000000000a39b4 /system/lib64/ndk/libffrt.so(ffrt_usleep+60)(22be57f01a789a03813d26a19c3a4042)
112#03 pc 0000000000420de0 /system/lib64/libbms.z.so(2eb52bd03af1b9a31e14ffe60bfc39da)
113#04 pc 00000000000a6a2c /system/lib64/ndk/libffrt.so(ffrt::CPUEUTask::Execute()+300)(22be57f01a789a03813d26a19c3a4042)
114#05 pc 0000000000066d18 /system/lib64/ndk/libffrt.so(22be57f01a789a03813d26a19c3a4042)
115```
116
117**Precautions**
118
119The DFX module has requirements on the processing time during freeze. There is a low probability that the information collected by `ffrt_dump` is incomplete and the freeze processing time expires. In this case, the information flushed to the disk is missing.
120
121### Blackbox Logs
122
123**Mechanism**
124
125When a process crashes, the FFRT module receives signals (`SIGABRT`, `SIGBUS`, `SIGFPE`, `SIGILL`, `SIGSTKFLT`, `SIGSTOP`, `SIGSYS`, and `SIGTRAP`) and saves important running information to the faultlog, including the running task, running information and call stack information of the current Worker thread, common task information, and queue task information. You can use the information to locate the crashes.
126
127**Example**
128
129```txt
130C01719/CameraDaemon/ffrt: 9986:operator():254 <<<=== ffrt black box(BBOX) start ===>>>
131C01719/CameraDaemon/ffrt: 9987:SaveCurrent:63 <<<=== current status ===>>>
132C01719/CameraDaemon/ffrt: 9988:SaveCurrent:68 signal SIGABRT triggered: source tid 5962, task id 17, qos 2, name SvrWatchdog
133C01719/CameraDaemon/ffrt: 9989:SaveWorkerStatus:94 <<<=== worker status ===>>>
134C01719/CameraDaemon/ffrt: 9990:SaveWorkerStatus:100 qos 0: worker tid 6410 is running nothing
135C01719/CameraDaemon/ffrt: 9991:SaveWorkerStatus:100 qos 2: worker tid 5968 is running nothing
136C01719/CameraDaemon/ffrt: 9992:SaveWorkerStatus:100 qos 2: worker tid 5964 is running nothing
137C01719/CameraDaemon/ffrt: 9993:SaveWorkerStatus:100 qos 2: worker tid 5963 is running nothing
138C01719/CameraDaemon/ffrt: 9994:SaveWorkerStatus:105 qos 2: worker tid 5962 is running task id 17 name SvrWatchdog
139C01719/CameraDaemon/ffrt: 9995:SaveWorkerStatus:100 qos 2: worker tid 5967 is running nothing
140C01719/CameraDaemon/ffrt: 9996:SaveWorkerStatus:100 qos 2: worker tid 5965 is running nothing
141C01719/CameraDaemon/ffrt: 9997:SaveWorkerStatus:100 qos 2: worker tid 5961 is running nothing
142C01719/CameraDaemon/ffrt: 9998:SaveWorkerStatus:100 qos 2: worker tid 1146 is running nothing
143C01719/CameraDaemon/ffrt: 9999:SaveWorkerStatus:100 qos 2: worker tid 1145 is running nothing
144C01719/CameraDaemon/ffrt: 10000:SaveWorkerStatus:100 qos 2: worker tid 5966 is running nothing
145```
146
147**Precautions**
148
149N/A
150
151### Tracing
152
153**Mechanism**
154
155During FFRT task scheduling and execution, the system traces the task status in the FFRT framework in real time. You can use the trace graphical tool to analyze whether the task behavior meets the expectation.
156
157**Example**
158
1591. Starting trace capture
160
161    ```shell
162    hdc shell "hitrace -t 10 -b 20480 -o /data/local/tmp/in_systrace.ftrace sched freq idle ffrt"
163    # -t: specifies the trace collection duration, during which all trace records are flushed to the disk.
164    # -b: specifies the size of the trace record cache. If the buffer is insufficient, some records may be overwritten and not flushed to disks.
165    # -o: specifies the path for storing trace files.
166    ```
167
1682. Using a graphical tool
169
170    Obtain the trace file from the device and use a graphical tool, for example, [Perfetto](https://perfetto.dev/), to analyze the file.
171
172**Precautions**
173
174You can also add traces to your service code to locate the fault. Note that in the high-frequency call process, adding traces will cause system overhead and affect service performance.
175
176### Debug Logs
177
178**Mechanism**
179
180- By default, debug logs are disabled for the FFRT, but can be enabled by using commands to obtain more maintenance and test information for fault locating in the development.
181- Enable the FFRT debug log function:
182
183    ```shell
184    hdc shell hilog -b DEBUG -D 0xD001719
185    ```
186
187- Restore the default FFRT INFO log level.
188
189    ```shell
190    hdc shell hilog -b INFO -D 0xD001719
191    ```
192
193**Example**
194
195```txt
1964190  5631 D C01719/neboard:EngineServiceAbility:1/ffrt: 275337:Detach:147 qos 3 thread not joinable
1973257  6075 D C01719/com.ohos.sceneboard/ffrt: 513070:SetDefaultThreadAttr:148 qos apply tid[6075] level[3]
198```
199
200**Precautions**
201
202The FFRT is the system base and supports the running of a large number of upper-layer services and frameworks. If the debug log function is enabled globally, the number of logs will exceed the threshold, which affects the log output of other modules.
203
204## How to Develop
205
206The following describes how to use the native APIs provided by FFRT to create parallel tasks and serial queue tasks and destroy corresponding resources.
207
2081. Add a dynamic link library to the `CMakeLists.txt` project.
209
210    ```txt
211    libffrt.z.so
212    ```
213
2142. Include the following header files in the project.
215
216    ```cpp
217    #include "ffrt/task.h"
218    #include "ffrt/mutex.h"
219    #include "ffrt/shared_mutex.h"
220    #include "ffrt/condition_variable.h"
221    #include "ffrt/sleep.h"
222    #include "ffrt/queue.h"
223    #include "ffrt/loop.h"
224    #include "ffrt/timer.h"
225    ```
226
2273. Encapsulate the function to be executed.
228
229    ```cpp
230    // Method 1: Use the template. C++ is supported.
231    template<class T>
232    struct function {
233        ffrt_function_header_t header;
234        T closure;
235    };
236
237    template<class T>
238    void exec_function_wrapper(void* t)
239    {
240        auto f = reinterpret_cast<function<std::decay_t<T>>*>(t);
241        f->closure();
242    }
243
244    template<class T>
245    void destroy_function_wrapper(void* t)
246    {
247        auto f = reinterpret_cast<function<std::decay_t<T>>*>(t);
248        f->closure = nullptr;
249    }
250
251    template<class T>
252    inline ffrt_function_header_t* create_function_wrapper(T&& func,
253        ffrt_function_kind_t kind = ffrt_function_kind_general)
254    {
255        using function_type = function<std::decay_t<T>>;
256        static_assert(sizeof(function_type) <= ffrt_auto_managed_function_storage_size,
257            "size of function must be less than ffrt_auto_managed_function_storage_size");
258
259        auto p = ffrt_alloc_auto_managed_function_storage_base(kind);
260        auto f = new (p)function_type;
261        f->header.exec = exec_function_wrapper<T>;
262        f->header.destroy = destroy_function_wrapper<T>;
263        f->closure = std::forward<T>(func);
264        return reinterpret_cast<ffrt_function_header_t*>(f);
265    }
266
267    // Method 2
268    typedef struct {
269        ffrt_function_header_t header;
270        ffrt_function_t func;
271        ffrt_function_t after_func;
272        void* arg;
273    } ffrt_function_wrapper_t;
274
275    static inline void ffrt_exec_function_wrapper(void* t)
276    {
277       ffrt_function_wrapper_t* f = (ffrt_function_wrapper_t *)t;
278       if (f->func) {
279           f->func(f->arg);
280       }
281    }
282
283    static inline void ffrt_destroy_function_wrapper(void* t)
284    {
285        ffrt_function_wrapper_t* f = (ffrt_function_wrapper_t *)t;
286        if (f->after_func) {
287            f->after_func(f->arg);
288        }
289    }
290
291    #define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
292    static inline ffrt_function_header_t *ffrt_create_function_wrapper(ffrt_function_t func,
293        ffrt_function_t after_func, void* arg, ffrt_function_kind_t kind)
294    {
295        FFRT_STATIC_ASSERT(sizeof(ffrt_function_wrapper_t) <= ffrt_auto_managed_function_storage_size,
296            size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
297
298        ffrt_function_wrapper_t* f = (ffrt_function_wrapper_t *)ffrt_alloc_auto_managed_function_storage_base(kind);
299        f->header.exec = ffrt_exec_function_wrapper;
300        f->header.destroy = ffrt_destroy_function_wrapper;
301        f->func = func;
302        f->after_func = after_func;
303        f->arg = arg;
304        return (ffrt_function_header_t *)f;
305    }
306
307    // Example: function to be submitted for execution.
308    void OnePlusForTest(void* arg)
309    {
310        (*static_cast<int*>(arg)) += 1;
311    }
312    ```
313
3144. Set task attributes, including the QoS level and task name.
315
316    ```cpp
317    // ******Initialize the attributes of the parallel task******
318    ffrt_task_attr_t attr;
319    ffrt_task_attr_init(&attr);
320
321    // ******Create a serial queue******
322
323    // Create the attributes of the serial queue.
324    ffrt_queue_attr_t queue_attr;
325    // Create the handle to the serial queue.
326    ffrt_queue_t queue_handle;
327
328    // Initialize the queue attribute.
329    (void)ffrt_queue_attr_init(&queue_attr);
330
331    // Set the QoS if necessary.
332    ffrt_queue_attr_set_qos(&queue_attr, static_cast<ffrt_qos_t>(ffrt_qos_inherit));
333    // Set the timeout period (ms) if necessary.
334    ffrt_queue_attr_set_timeout(&queue_attr, 10000);
335    // Set the timeout callback if necessary.
336    int x = 0;
337    ffrt_queue_attr_set_callback(&queue_attr, ffrt_create_function_wrapper(OnePlusForTest, NULL, &x,
338        ffrt_function_kind_queue));
339
340    // Initialize the queue based on the attributes.
341    queue_handle = ffrt_queue_create(ffrt_queue_serial, "test_queue", &queue_attr);
342    ```
343
3445. Submit the task.
345
346    ```cpp
347    int a = 0;
348    // ******Parallel task******
349    // Submit the parallel task without obtaining a handle.
350    ffrt_submit_base(
351        ffrt_create_function_wrapper(OnePlusForTest, NULL, &a, ffrt_function_kind_general), NULL, NULL, &attr);
352    // Submit the parallel task and obtain a handle.
353    ffrt_task_handle_t task = ffrt_submit_h_base(
354        ffrt_create_function_wrapper(OnePlusForTest, NULL, &a, ffrt_function_kind_general), NULL, NULL, &attr);
355
356    // ******Serial queue task******
357    // Submit the serial queue task without obtaining a handle.
358    ffrt_queue_submit(queue_handle,
359        ffrt_create_function_wrapper(OnePlusForTest, NULL, &a, ffrt_function_kind_queue), NULL);
360    // Submit the serial queue task and obtain a handle.
361    ffrt_task_handle_t handle = ffrt_queue_submit_h(queue_handle,
362        ffrt_create_function_wrapper(OnePlusForTest, NULL, &a, ffrt_function_kind_queue), NULL);
363
364    // Call wait if you need to wait for the execution result.
365    const std::vector<ffrt_dependence_t> wait_deps = {{ffrt_dependence_task, task}};
366    ffrt_deps_t wait{static_cast<uint32_t>(wait_deps.size()), wait_deps.data()};
367    ffrt_wait_deps(&wait);
368
369    ffrt_queue_wait(handle);
370    ```
371
3726. (Optional) If a task does not need to be destroyed, you can submit the task through a simplified API.
373
374    ```cpp
375    int a = 0;
376    // If the after_func function pointer in step 3 is NULL, you can use the simplified API to submit a task to avoid redundant task structure encapsulation.
377    // ******Parallel task******
378    // Submit a parallel task without a handle through a simplified API.
379    ffrt_submit_f(OnePlusForTest, &a, NULL, NULL, &attr);
380    // Submit a parallel task with a handle through a simplified API.
381    ffrt_task_handle_t task = ffrt_submit_h_f(OnePlusForTest, &a, NULL, NULL, &attr);
382
383    // ******Serial queue task******
384    // Submit a serial queue task that does not return a handle through a simplified API.
385    ffrt_queue_submit_f(queue_handle, OnePlusForTest, &a, NULL);
386    // Submit a serial queue task with a handle through a simplified API.
387    ffrt_task_handle_t handle = ffrt_queue_submit_h_f(queue_handle, OnePlusForTest, &a, NULL);
388
389    // Call wait if you need to wait for the execution result.
390    const std::vector<ffrt_dependence_t> wait_deps = {{ffrt_dependence_task, task}};
391    ffrt_deps_t wait{static_cast<uint32_t>(wait_deps.size()), wait_deps.data()};
392    ffrt_wait_deps(&wait);
393
394    ffrt_queue_wait(handle);
395    ```
396
3977. Destroy the resources after the task is submitted.
398
399    ```cpp
400    // ******Destroy the parallel task******
401    ffrt_task_attr_destroy(&attr);
402    ffrt_task_handle_destroy(task);
403
404    // ******Destroy the serial queue task******
405    // Destroy the task handle and then the queue.
406    ffrt_queue_attr_destroy(&queue_attr);
407    ffrt_task_handle_destroy(handle);
408    ffrt_queue_destroy(queue_handle);
409    ```
410
411## Suggestions
412
413### Suggestion 1: Functional Programming
414
415- Use pure functions and encapsulate them to express each step of the process.
416- There is no global data access.
417- There is no internal state reserved.
418- Call the `ffrt_submit_base()` or `ffrt_submit_f()` API to submit a function in asynchronous mode.
419- 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.
420- Programmers use the `in_deps` and `out_deps` parameters to express task dependencies to ensure the correctness of program execution.
421
422> Using pure functions helps you maximize the parallelism and avoid data races and lock abuse.
423>
424> In practice, you may not use pure functions in certain scenarios, with the following prerequisites:
425>
426> - `in_deps` and `out_deps` can ensure the correctness of program execution.
427> - The lock mechanism provided by FFRT is used to protect access to global variables.
428
429### Suggestion 2: Using FFRT APIs
430
431- Do not use the APIs of the system thread library to create threads in FFRT tasks. Instead, use `submit` to submit tasks.
432- Use the lock, condition variable, sleep, and I/O APIs provided by FFRT to replace the APIs of the system thread library.
433  - Using the APIs of the system thread library may block worker threads and result in extra performance overhead.
434
435### Suggestion 3: Deadline Mechanism
436
437- Use FFRT APIs in processing flows that feature periodic/repeated execution.
438- Use FFRT APIs in processing flows with clear time constraints and is performance critical.
439- Use FFRT APIs in relatively large-granularity processing flows, such as the frame processing flow with the 16.6 ms time constraint.
440
441### Suggestion 4: Migration from the Thread Model
442
443- Create a thread instead of creating an FFRT task.
444  - A thread is logically similar to a task without `in_deps`.
445- Identify the dependency between threads and express the dependencies in `in_deps` and `out_deps` of the task.
446- Decompose an intra-thread computing process into asynchronous tasks for invoking.
447- Use the task dependency and lock mechanism to avoid data races of concurrent tasks.
448
449### Suggestion 5: C++ APIs Recommended
450
451- The FFRT C++ APIs are implemented based on the C APIs. Before using the APIs, you can manually add the C++ header file.
452
453## Constraints
454
455### Thread Local Variables
456
457Risks exist when thread local variables are used in FFRT tasks. The details are as follows:
458
459- Thread local variables include the variables defined by `thread_local` provided by C/C++ and the variables created by using `thread_local`.
460- FFRT supports task scheduling. The thread to which a task is scheduled is random. Therefore, there are risks to use thread local variables, which is consistent with all other frameworks that support concurrent task scheduling.
461- By default, an FFRT task runs in coroutine mode. During task execution, the coroutine may exit. When the task is resumed, the thread that executes the task may change.
462
463### Thread Binding
464
465- FFRT supports task scheduling. The thread to which a task is scheduled is random. Thread-bound behaviors, such as thread_idx, thread priority, and thread affinity, cannot be used in tasks.
466
467### Synchronization Primitives in the Standard Library
468
469Using the standard library's recursive mutex in FFRT tasks may lead to deadlocks. It is necessary to replace it with the recursive mutex provided by FFRT. The details are as follows:
470
471- When `lock()` is successfully executed, the recursive mutex records the execution stack of the caller as the lock owner. If the caller is the current execution stack, a success message is returned to support nested lock acquisition within the same execution stack. In the standard library, the execution stack is identified by the thread ID.
472- When using the standard library's recursive mutex in FFRT tasks, if a task (coroutine) exits between the outer and inner `lock()` calls and resumes execution on a different FFRT Worker thread than the one where `lock()` was initially called, the current thread will not be recognized as the owner. This causes the `lock()` to fail, suspends the FFRT Worker thread, and prevents the subsequent `unlock()` from executing, leading to a deadlock.
473
474### Support for the Process `fork()` Scenario
475
476- Create a child process in a process that does not use FFRT. FFRT can be used in the child process.
477- Create a child process using `fork()` in a process that uses FFRT. FFRT cannot be used in the child process.
478- Create a child process using `fork()` and `exec()` in a process that uses FFRT. FFRT can be used in the child process.
479
480### Dynamic FFRT Deployment
481
482- Static library deployment may cause multi-instance problems. For example, when multiple .so files loaded by the same process use FFRT in static library mode, FFRT is instantiated into multiple copies, and their behavior is unknown.
483
484### Limited Number of Input and Output Dependencies
485
486- For `ffrt_submit_base`, the total number of input dependencies and output dependencies of each task cannot exceed 8.
487- For `ffrt_submit_h_base`, the total number of input dependencies and output dependencies of each task cannot exceed 7.
488- When a parameter is used as both an input dependency and an output dependency, it is counted as one dependency. For example, if the input dependency is `{&x}` and the output dependency is also `{&x}`, then the number of dependencies is 1.
489
490### Restrictions on Process or Thread Exit
491
492- When a process exits, the shared resources in the process, such as the thread pool in the FFRT, have been released. **submit()** should not be called.
493- When a thread exits, the thread local resources in the FFRT have been released. **submit()** should not be called for the thread that is exiting.
494
495## Common Anti-Patterns
496
497### After an FFRT object is initialized in the C code, you are responsible for setting the object to null or destroying the object.
498
499- To 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.
500- Noncompliant example 1: Repeated calling of destroy() may cause unpredictable data damage.
501
502    ```cpp
503    #include <stdio.h>
504    #include "ffrt/cpp/task.h"
505
506    void abnormal_case_1()
507    {
508        ffrt_task_handle_t h = ffrt_submit_h_base(
509            ffrt::create_function_wrapper(std::function<void()>([](){ printf("Test task running...\n"); })),
510            NULL, NULL, NULL);
511        // ...
512        ffrt_task_handle_destroy(h);
513        ffrt_task_handle_destroy(h); // Repeated release
514    }
515    ```
516
517- Noncompliant example 2: No calling of destroy() may cause memory leak.
518
519    ```cpp
520    #include <stdio.h>
521    #include "ffrt/cpp/task.h"
522
523    void abnormal_case_2()
524    {
525        ffrt_task_handle_t h = ffrt_submit_h_base(
526            ffrt::create_function_wrapper(std::function<void()>([](){ printf("Test task running...\n"); })),
527            NULL, NULL, NULL);
528        // ...
529        // Memory leak
530    }
531    ```
532
533- Recommended example: Call **destroy()** only once. You can leave it empty if necessary.
534
535    ```cpp
536    #include <stdio.h>
537    #include "ffrt/cpp/task.h"
538
539    void normal_case()
540    {
541        ffrt_task_handle_t h = ffrt_submit_h_base(
542            ffrt::create_function_wrapper(std::function<void()>([](){ printf("Test task running...\n"); })),
543            NULL, NULL, NULL);
544        // ...
545        ffrt_task_handle_destroy(h);
546        h = nullptr; // Set the task handle variable to null if necessary.
547    }
548    ```
549
550### Incorrect Variable Lifecycle
551
552- When submitting an FFRT task, pay attention to the misuse of objects or resources during their lifecycle. These misuses may cause program breakdown, data damage, or difficult debugging.
553- Noncompliant example 1: Ended variable lifecycle causes a UAF problem.
554
555    ```cpp
556    #include <unistd.h>
557    #include "ffrt/cpp/task.h"
558
559    void abnormal_case_3()
560    {
561        int x = 0;
562        ffrt::submit([&] {
563            usleep(1000); // Simulate the service processing logic.
564            x++;          // The variable lifecycle may have ended, and a UAF problem may occur when the variable is accessed.
565        });
566    }
567    ```
568
569- Noncompliant example 2: Ended mutex lifecycle causes function exceptions.
570
571    ```cpp
572    #include <unistd.h>
573    #include "ffrt/cpp/mutex.h"
574    #include "ffrt/cpp/task.h"
575
576    void abnormal_case_4()
577    {
578        ffrt::mutex lock;
579        ffrt::submit([&] {
580            lock.lock();   // When performing operations on the FFRT lock, ensure that the lifecycle of the FFRT lock is valid.
581            usleep(1000);  // Simulate the service processing logic.
582            lock.unlock(); // When performing operations on the FFRT lock, ensure that the lifecycle of the FFRT lock is valid.
583        });
584    }
585    ```
586
587## Using FFRT in DevEco Studio
588
589### Using FFRT C API
590
591Native Development Kit (NDK) is a toolset provided by the system. It offers native APIs that allow you to implement key application functions using C or C++ code.
592
593The FFRT C APIs have been integrated into the NDK. You can directly use the corresponding API in DevEco Studio.
594
595```c
596#include "ffrt/task.h"
597#include "ffrt/mutex.h"
598#include "ffrt/shared_mutex.h"
599#include "ffrt/condition_variable.h"
600#include "ffrt/sleep.h"
601#include "ffrt/queue.h"
602#include "ffrt/loop.h"
603#include "ffrt/timer.h"
604#include "ffrt/type_def.h"
605```
606
607### Using FFRT C++ API
608
609The FFRT deployment depends on the FFRT dynamic library `libffrt.so` and a group of header files. The dynamic library exports only C APIs, and C++ APIs call C APIs. In addition, C++ elements in APIs are compiled into the dynamic library based on the header files, ensuring ABI compatibility.
610
611![image](figures/ffrt_figure7.png)
612
613To use FFRT C++ APIs, you need to use the third-party library [@ppd/ffrt](https://ohpm.openharmony.cn/#/en/detail/@ppd%2Fffrt), which is officially maintained by FFRT.
614
615Run the following command in the module directory to install the third-party library:
616
617```shell
618ohpm install @ppd/ffrt
619```
620
621You can also configure the dependencies in the `oh-package.json5` file so that the third-party library can be automatically downloaded and installed through DevEco Studio.
622
623Add the header file search path and link dependency to the `CMakeLists.txt` file.
624
625```cmake
626# ${MODULES_PATH} indicates the installation path of the third-party library. You need to define the path or replace it with an absolute or relative path.
627include_directories(${MODULES_PATH}/@ppd/ffrt/include)
628target_link_libraries(${TARGET_NAME} PUBLIC libffrt.z.so)
629```
630
631Use the FFRT C++ API in the code.
632
633```cpp
634// include all C or C++ header files
635#include "ffrt/ffrt.h"
636
637// include specified header files
638#include "ffrt/cpp/task.h"
639#include "ffrt/cpp/mutex.h"
640#include "ffrt/cpp/shared_mutex.h"
641#include "ffrt/cpp/condition_variable.h"
642#include "ffrt/cpp/sleep.h"
643#include "ffrt/cpp/queue.h"
644```
645