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 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