• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Function Flow Runtime 开发指导
2
3## 场景介绍
4
5Function Flow编程模型是一种基于任务和数据驱动的并发编程模型,允许开发者通过任务及其依赖关系描述的方式进行应用开发。FFRT(Function Flow运行时)是支持Function Flow编程模型的软件运行时库,用于调度执行开发者基于Function Flow编程模型开发的应用。通过Function Flow编程模型和FFRT,开发者可专注于应用功能开发,由FFRT在运行时根据任务依赖状态和可用执行资源自动并发调度和执行任务。
6
7本文用于指导开发者基于Function Flow编程模型和FFRT实现并行编程。
8
9## 接口说明
10
11| 接口名                                                       | 描述                                                         |
12| ------------------------------------------------------------ | ------------------------------------------------------------ |
13| ffrt_condattr_init (ffrt_condattr_t* attr) | 初始化条件变量属性。 |
14| ffrt_condattr_destroy(ffrt_condattr_t* attr)  | 销毁条件变量属性。 |
15| ffrt_condattr_setclock(ffrt_condattr_t* attr, ffrt_clockid_t clock) | 设置条件变量的时钟属性。 |
16| ffrt_condattr_getclock(const ffrt_condattr_t* attr, ffrt_clockid_t* clock)        | 获取条件变量的时钟属性。              |
17| ffrt_cond_init(ffrt_cond_t* cond, const ffrt_condattr_t* attr)   | 初始化条件变量。      |
18| ffrt_cond_signal(ffrt_cond_t* cond)         | 唤醒阻塞在条件变量上的一个任务。 |
19| ffrt_cond_broadcast(ffrt_cond_t* cond) | 唤醒阻塞在条件变量上的所有任务。 |
20| ffrt_cond_wait(ffrt_cond_t* cond, ffrt_mutex_t* mutex)            | 条件变量等待函数,条件变量不满足时阻塞当前任务。 |
21| ffrt_cond_timedwait(ffrt_cond_t* cond, ffrt_mutex_t* mutex, const struct timespec* time_point)            | 条件变量超时等待函数,条件变量不满足时阻塞当前任务,超时等待返回。 |
22| ffrt_cond_destroy(ffrt_cond_t* cond)            | 销毁条件变量。 |
23| ffrt_mutex_init(ffrt_mutex_t* mutex, const ffrt_mutexattr_t* attr) | 初始化mutex。 |
24| ffrt_mutex_lock(ffrt_mutex_t* mutex)   | 获取mutex。 |
25| ffrt_mutex_unlock(ffrt_mutex_t* mutex)  | 释放mutex。 |
26| ffrt_mutex_trylock(ffrt_mutex_t* mutex)   | 尝试获取mutex。 |
27| ffrt_mutex_destroy(ffrt_mutex_t* mutex)   | 销毁mutex。 |
28| ffrt_queue_attr_init(ffrt_queue_attr_t* attr)    | 初始化串行队列属性。 |
29| ffrt_queue_attr_destroy(ffrt_queue_attr_t* attr)    | 销毁串行队列属性。 |
30| ffrt_queue_attr_set_qos(ffrt_queue_attr_t* attr, ffrt_qos_t qos)    | 设置串行队列qos属性。 |
31| ffrt_queue_attr_get_qos(const ffrt_queue_attr_t* attr)      | 获取串行队列qos属性。 |
32| ffrt_queue_create(ffrt_queue_type_t type, const char* name, const ffrt_queue_attr_t* attr)   | 创建队列。 |
33| ffrt_queue_destroy(ffrt_queue_t queue)   | 销毁队列。 |
34| ffrt_queue_submit(ffrt_queue_t queue, ffrt_function_header_t* f, const ffrt_task_attr_t* attr)   | 提交一个任务到队列中调度执行。 |
35| ffrt_queue_submit_h(ffrt_queue_t queue, ffrt_function_header_t* f, const ffrt_task_attr_t* attr)  | 提交一个任务到队列中调度执行,并返回任务句柄。 |
36| ffrt_queue_wait(ffrt_task_handle_t handle)    | 等待队列中一个任务执行完成。 |
37| ffrt_queue_cancel(ffrt_task_handle_t handle)     | 取消队列中一个任务。 |
38| ffrt_usleep(uint64_t usec)   | 延迟usec微秒。 |
39| ffrt_yield(void)     | 当前任务主动放权,让其他任务有机会调度执行。 |
40| ffrt_task_attr_init(ffrt_task_attr_t* attr)     | 初始化任务属性。 |
41| ffrt_task_attr_set_name(ffrt_task_attr_t* attr, const char* name)   | 设置任务名字。 |
42| ffrt_task_attr_get_name(const ffrt_task_attr_t* attr)   | 获取任务名字。 |
43| ffrt_task_attr_destroy(ffrt_task_attr_t* attr)    | 销毁任务属性。 |
44| ffrt_task_attr_set_qos(ffrt_task_attr_t* attr, ffrt_qos_t qos)    | 设置任务qos。 |
45| ffrt_task_attr_get_qos(const ffrt_task_attr_t* attr)      | 获取任务qos。 |
46| ffrt_task_attr_set_delay(ffrt_task_attr_t* attr, uint64_t delay_us)    | 设置任务延迟时间。 |
47| ffrt_task_attr_get_delay(const ffrt_task_attr_t* attr)      | 获取任务延迟时间。 |
48| ffrt_this_task_update_qos(ffrt_qos_t qos)    | 更新任务qos。 |
49| ffrt_this_task_get_id(void)    | 获取任务id。 |
50| ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_t kind)     | 申请函数执行结构的内存。 |
51| 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)   | 提交任务调度执行。 |
52| 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)    | 提交任务调度执行并返回任务句柄。 |
53| ffrt_task_handle_destroy(ffrt_task_handle_t handle)    | 销毁任务句柄。 |
54| ffrt_skip(ffrt_task_handle_t handle)     | 跳过指定任务。 |
55| ffrt_wait_deps(const ffrt_deps_t* deps)    | 等待依赖的任务完成,当前任务开始执行。 |
56
57
58
59## 函数介绍
60
61
62### 任务管理
63
64#### ffrt_submit_base
65
66* 该接口为ffrt动态库的导出接口,基于此可以封装出C API ffrt_submit,满足二进制兼容。
67
68##### 声明
69
70```{.c}
71const int ffrt_auto_managed_function_storage_size = 64 + sizeof(ffrt_function_header_t);
72typedef enum {
73    ffrt_function_kind_general,
74    ffrt_function_kind_queue
75} ffrt_function_kind_t;
76
77void* ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_t kind);
78
79typedef void(*ffrt_function_t)(void*);
80typedef struct {
81    ffrt_function_t exec;
82    ffrt_function_t destroy;
83    uint64_t reserve[2];
84} ffrt_function_header_t;
85
86void 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);
87```
88
89##### 参数
90
91`kind`
92
93* function子类型,用于优化内部数据结构,默认使用ffrt_function_kind_general类型。
94
95`func`
96
97* CPU Function的指针,该指针执行的数据结构,按照`ffrt_function_header_t`定义的描述了该CPU Task如何执行和销毁的函数指针,FFRT通过这两个函数指针完成Task的执行和销毁。
98
99`in_deps`
100
101* 该参数是可选的。
102* 该参数用于描述该任务的输入依赖,FFRT 通过数据的虚拟地址作为数据的Signature 来建立依赖。
103
104`out_deps`
105
106* 该参数是可选的。
107* 该参数用于描述该任务的输出依赖。
108* `注意`:该依赖值本质上是一个数值,ffrt没办法区分该值是合理的还是不合理的,会假定输入的值是合理的进行处理;但不建议采用NULL,1, 2 等值来建立依赖关系,建议采用实际的内存地址,因为前者使用不当会建立起不必要的依赖,影响并发。
109
110`attr`
111
112* 该参数是可选的。
113* 该参数用于描述Task 的属性,比如qos 等,详见 [ffrt_task_attr_t](#ffrt_task_attr_t)章节。
114
115##### 返回值
116
117* 不涉及。
118
119##### 描述
120* 建议用户对ffrt_submit_base进行封装后调用,具体可参考样例。
121* **ffrt_submit_base作为底层能力,使用时需要满足以下限制:**
122  * ffrt_submit_base入参中的func指针只能通过ffrt_alloc_auto_managed_function_storage_base申请,且二者的调用需一一对应。
123  * ffrt_alloc_auto_managed_function_storage_base申请的内存为ffrt_auto_managed_function_storage_size字节,其生命周期归ffrt管理,在该task结束时,由FFRT自动释放,用户无需释放。
124* ffrt_function_header_t 中定义了两个函数指针:
125  * exec:用于描述该Task如何被执行,当FFRT需要执行该Task时由FFRT调用。
126  * destroy:用于描述该Task如何被销毁,当FFRT需要销毁该Task时由FFRT调用。
127
128##### 样例
129
130
131```{.c}
132template<class T>
133struct function {
134    template<class CT>
135    function(ffrt_function_header_t h, CT&& c) : header(h), closure(std::forward<CT>(c)) {}
136    ffrt_function_header_t header;
137    T closure;
138};
139
140template<class T>
141void exec_function_wrapper(void* t)
142{
143    auto f = (function<std::decay_t<T>>*)t;
144    f->closure();
145}
146
147template<class T>
148void destroy_function_wrapper(void* t)
149{
150    auto f = (function<std::decay_t<T>>*)t;
151    f->closure = nullptr;
152}
153
154template<class T>
155inline ffrt_function_header_t* create_function_wrapper(T&& func)
156{
157    using function_type = function<std::decay_t<T>>;
158    static_assert(sizeof(function_type) <= ffrt_auto_managed_function_storage_size,
159        "size of function must be less than ffrt_auto_managed_function_storage_size");
160
161    auto p = ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
162    auto f = new (p) function_type(
163        {exec_function_wrapper<T>, destroy_function_wrapper<T>},
164        std::forward<T>(func));
165    return (ffrt_function_header_t*)f;
166}
167
168static inline void submit(std::function<void()>&& func)
169{
170    return ffrt_submit_base(create_function_wrapper(std::move(func)), NULL, NULL, NULL);
171}
172```
173
174#### ffrt_wait
175
176<hr/>
177* 同步等待,与ffrt_submit_base 配合使用。
178* 等待指定的数据被生产完成,或等待当前任务的所有子任务完成,在不满足条件之前,当前的执行上下文被suspend,在满足条件后恢复执行。
179
180##### 声明
181
182```{.c}
183void ffrt_wait_deps(ffrt_deps_t* deps);
184void ffrt_wait();
185```
186
187##### 参数
188
189`deps`
190
191* 需要等待被生产完成的数据的虚拟地址,这些地址可能作为某些任务在submit 时的out_deps,该依赖的生成见ffrt_deps_t章节,空指针表示无依赖。
192
193##### 返回值
194
195* 不涉及。
196
197##### 描述
198* ffrt_wait_deps(deps) 用于等待deps指代的数据被生产完成才能执行后面的代码。
199* ffrt_wait() 用于等待当前上下文提交的所有子任务(`注意:不包括孙任务和下级子任务`)都完成才能执行后面的代码。
200* 该接口支持在FFRT task 内部调用,也支持在FFRT task 外部调用。
201* 在FFRT task 外部调用的wait 是OS 能够感知的等待,相对于FFRT task 内部调用的wait 是更加昂贵的,因此我们希望尽可能让更多的wait 发生在FFRT task 内部 ,而不是FFRT task 外部。
202
203##### 样例
204
205**recursive fibonacci**
206
207串行版的fibonacci 可以实现为:
208
209```{.c}
210#include <stdio.h>
211
212void fib(int x, int* y) {
213    if (x <= 1) {
214        *y = x;
215    } else {
216        int y1, y2;
217        fib(x - 1, &y1);
218        fib(x - 2, &y2);
219        *y = y1 + y2;
220    }
221}
222int main(int narg, char** argv)
223{
224    int r;
225    fib(10, &r);
226    printf("fibonacci 10: %d\n", r);
227    return 0;
228}
229```
230
231若要使用 FFRT 实现并行(注,对于单纯的fibonacci,单个 Task 的计算量极小,不具有并行加速的意义,但这种调用pattern 对并行编程模型的灵活性考验是非常高的),其中1种可行的实现为:
232
233```{.c}
234#include <stdio.h>
235#include "ffrt.h"  //包含所有ffrt涉及的头文件
236
237typedef struct {
238    int x;
239    int* y;
240} fib_ffrt_s;
241
242typedef struct {
243    ffrt_function_header_t header;
244    ffrt_function_t func;
245    ffrt_function_t after_func;
246    void* arg;
247} c_function;
248
249static void ffrt_exec_function_wrapper(void* t)
250{
251    c_function* f = (c_function*)t;
252    if (f->func) {
253        f->func(f->arg);
254    }
255}
256
257static void ffrt_destroy_function_wrapper(void* t)
258{
259    c_function* f = (c_function*)t;
260    if (f->after_func) {
261        f->after_func(f->arg);
262    }
263}
264
265#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
266static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
267    const ffrt_function_t after_func, void* arg)
268{
269    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
270        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
271    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
272    f->header.exec = ffrt_exec_function_wrapper;
273    f->header.destroy = ffrt_destroy_function_wrapper;
274    f->func = func;
275    f->after_func = after_func;
276    f->arg = arg;
277    return (ffrt_function_header_t*)f;
278}
279
280static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
281    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
282{
283    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
284}
285
286#define ffrt_deps_define(name, dep1, ...) const void* __v_##name[] = {dep1, ##__VA_ARGS__}; \
287    ffrt_deps_t name = {sizeof(__v_##name) / sizeof(void*), __v_##name}
288
289void fib_ffrt(void* arg)
290{
291    fib_ffrt_s* p = (fib_ffrt_s*)arg;
292    int x = p->x;
293    int* y = p->y;
294
295    if (x <= 1) {
296        *y = x;
297    } else {
298        int y1, y2;
299        fib_ffrt_s s1 = {x - 1, &y1};
300        fib_ffrt_s s2 = {x - 2, &y2};
301        ffrt_deps_define(dx, &x);
302        ffrt_deps_define(dy1, &y1);
303        ffrt_deps_define(dy2, &y2);
304        ffrt_deps_define(dy12, &y1, &y2);
305        ffrt_submit_c(fib_ffrt, NULL, &s1, &dx, &dy1, NULL);
306        ffrt_submit_c(fib_ffrt, NULL, &s2, &dx, &dy2, NULL);
307        ffrt_wait_deps(&dy12);
308        *y = y1 + y2;
309    }
310}
311
312int main(int narg, char** argv)
313{
314    int r;
315    fib_ffrt_s s = {10, &r};
316    ffrt_deps_define(dr, &r);
317    ffrt_submit_c(fib_ffrt, NULL, &s, NULL, &dr, NULL);
318    ffrt_wait_deps(&dr);
319    printf("fibonacci 10: %d\n", r);
320    return 0;
321}
322```
323
324`解析`:
325
3261)   将fibonacci (x-1)和fibonacci (x-2) 作为2个Task 提交给FFRT,在两个Task 完成之后将结果累加;
327
3282)   虽然单个Task 只能拆分成2个SubTask 但是子Task 可以继续拆分,因此,整个计算图的并行度是非常高的,Task 之间在FFRT 内部形成了一颗调用树;
329
330<img src="figures/ffrtfigure2.png" style="zoom:100%" />
331
332> 以上实现,因为需要用户显式管理数据生命周期和函数入参打包两个因素,所以使得代码实现异常复杂。
333
334
335
336#### ffrt_deps_t
337
338* C API中对依赖数组的抽象,逻辑上等同于C++ API中的`std::vector<void*>`
339
340##### 声明
341
342```{.c}
343typedef enum {
344    ffrt_dependence_data,
345    ffrt_dependence_task,
346} ffrt_dependence_type_t;
347
348typedef struct {
349    ffrt_dependence_type_t type;
350    const void* ptr;
351} ffrt_dependence_t;
352
353typedef struct {
354    uint32_t len;
355    const ffrt_dependence_t* items;
356} ffrt_deps_t;
357```
358
359##### 参数
360
361`len`
362
363* 所依赖的Signature的个数,取值大于等于0。
364
365`item`
366
367* len个Signature的起始地址指针。
368
369`type`
370
371* 当前依赖为数据依赖还是任务依赖。
372
373`ptr`
374
375* 所依赖对应Signature内容的实际地址。
376
377##### 返回值
378
379* 不涉及。
380
381##### 描述
382
383* item为len个Signature的起始指针,该指针可以指向堆空间,也可以指向栈空间,但是要求分配的空间大于等于len * sizeof(ffrt_dependence_t)。
384
385##### 样例
386
387* 创建数据依赖或者任务依赖:
388
389```{.c}
390// 创建数据依赖的ffrt_deps_t
391int x = 0;
392const std::vector<ffrt_dependence_t> in_deps = {{ffrt_dependence_data, &x}};
393ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.data()};
394
395// 提交某个返回handle任务
396ffrt_task_handle_t task = ffrt_submit_h_base(
397        ffrt_create_function_wrapper(OnePlusForTest, NULL, &a), NULL, NULL, &attr);
398// 创建任务依赖的ffrt_deps_t
399const std::vector<ffrt_dependence_t> wait_deps = {{ffrt_dependence_task, task}};
400ffrt_deps_t wait{static_cast<uint32_t>(wait_deps.size()), wait_deps.data()};
401```
402
403#### ffrt_task_attr_t
404
405<hr/>
406* 定义task 的属性的辅助类,与ffrt_submit_base 配合使用。
407
408##### 声明
409
410```{.c}
411typedef enum {
412    ffrt_qos_inherent = -1,
413    ffrt_qos_background,
414    ffrt_qos_utility,
415    ffrt_qos_default,
416    ffrt_qos_user_initiated,
417} ffrt_qos_default_t;
418
419typedef int ffrt_qos_t;
420
421typedef struct {
422    uint32_t storage[(ffrt_task_attr_storage_size + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
423} ffrt_task_attr_t;
424typedef void* ffrt_task_handle_t;
425
426int ffrt_task_attr_init(ffrt_task_attr_t* attr);
427void ffrt_task_attr_destroy(ffrt_task_attr_t* attr);
428void ffrt_task_attr_set_qos(ffrt_task_attr_t* attr, ffrt_qos_t qos);
429ffrt_qos_t ffrt_task_attr_get_qos(const ffrt_task_attr_t* attr);
430void ffrt_task_attr_set_name(ffrt_task_attr_t* attr, const char* name);
431const char* ffrt_task_attr_get_name(const ffrt_task_attr_t* attr);
432void ffrt_task_attr_set_delay(ffrt_task_attr_t* attr, uint64_t delay_us);
433uint64_t ffrt_task_attr_get_delay(const ffrt_task_attr_t* attr);
434```
435
436##### 参数
437
438`attr`
439
440* 创建的tasks属性的句柄。
441
442`qos`
443
444* qos 设定的枚举类型。
445* inherent 是一个qos 设定策略,代表即将ffrt_submit 的task 的qos 继承当前task 的qos。
446
447`delay_us`
448
449* 任务延迟执行的时间,单位为us。
450
451##### 返回值
452
453* 不涉及。
454
455##### 描述
456* `attr`所传递的内容会在ffrt_submit内部完成取存,ffrt_submit返回后用户即可销毁。
457* 约定:
458  * 在submit 时,如果不通过task_attr 设定qos,那么默认该提交的task的qos 为`ffrt_qos_default`。
459  * 在submit 时,如果通过task_attr 设定qos 为`ffrt_qos_inherent`,表示将该提交的task 的qos 与当前task 的qos 相同,在FFRT task 外部提交的属性为`ffrt_qos_inherent` 的task,其qos 为`ffrt_qos_default`。
460  * 其他情况下,该提交的task 的qos 被设定为指定的值。
461* ffrt_task_attr_t对象的置空和销毁由用户完成,对同一个ffrt_task_attr_t仅能调用一次`ffrt_task_attr_destroy`,重复对同一个ffrt_task_attr_t调用`ffrt_task_attr_destroy`,其行为是未定义的。
462* 在`ffrt_task_attr_destroy`之后再对task_attr进行访问,其行为是未定义的。
463
464##### 样例
465
466* 提交一个qos 级别为background 的任务:
467
468```{.c}
469#include <stdio.h>
470#include "ffrt.h"
471
472void my_print(void* arg)
473{
474    printf("hello ffrt\n");
475}
476
477typedef struct {
478    ffrt_function_header_t header;
479    ffrt_function_t func;
480    ffrt_function_t after_func;
481    void* arg;
482} c_function;
483
484static void ffrt_exec_function_wrapper(void* t)
485{
486    c_function* f = (c_function*)t;
487    if (f->func) {
488        f->func(f->arg);
489    }
490}
491
492static void ffrt_destroy_function_wrapper(void* t)
493{
494    c_function* f = (c_function*)t;
495    if (f->after_func) {
496        f->after_func(f->arg);
497    }
498}
499
500#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
501static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
502    const ffrt_function_t after_func, void* arg)
503{
504    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
505        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
506    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
507    f->header.exec = ffrt_exec_function_wrapper;
508    f->header.destroy = ffrt_destroy_function_wrapper;
509    f->func = func;
510    f->after_func = after_func;
511    f->arg = arg;
512    return (ffrt_function_header_t*)f;
513}
514
515static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
516    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
517{
518    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
519}
520
521int main(int narg, char** argv)
522{
523    ffrt_task_attr_t attr;
524    ffrt_task_attr_init(&attr);
525    ffrt_task_attr_set_qos(&attr, ffrt_qos_background);
526    ffrt_task_attr_set_delay(&attr, 10000);
527    ffrt_submit_c(my_print, NULL, NULL, NULL, NULL, &attr);
528    ffrt_task_attr_destroy(&attr);
529    ffrt_wait();
530    return 0;
531}
532```
533
534
535
536
537#### ffrt_submit_h_base
538
539<hr/>
540
541* 向调度器提交一个task,与ffrt_submit_base 的差别在于返回task 的句柄,该句柄可以用于建立task 之间的依赖,或用于在wait 语句中实现同步。
542
543##### 声明
544
545```{.c}
546typedef void* ffrt_task_handle_t;
547
548ffrt_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);
549void ffrt_task_handle_destroy(ffrt_task_handle_t handle);
550```
551
552##### 参数
553
554`func`
555
556* CPU Function的指针,该指针执行的数据结构,按照`ffrt_function_header_t`定义的描述了该CPU Task如何执行和销毁的函数指针,FFRT通过这两个函数指针完成Task的执行和销毁。
557
558`in_deps`
559
560* 该参数是可选的。
561* 该参数用于描述该任务的输入依赖,FFRT 通过数据的虚拟地址作为数据的Signature 来建立依赖。
562
563`out_deps`
564
565* 该参数是可选的。
566* 该参数用于描述该任务的输出依赖。
567* `注意`:该依赖值本质上是一个数值,ffrt没办法区分该值是合理的还是不合理的,会假定输入的值是合理的进行处理;但不建议采用NULL,1, 2 等值来建立依赖关系,建议采用实际的内存地址,因为前者使用不当会建立起不必要的依赖,影响并发。
568
569`attr`
570
571* 该参数是可选的。
572* 该参数用于描述Task 的属性,比如qos 等,详见 [ffrt_task_attr_t](#ffrt_task_attr_t)章节。
573
574##### 返回值
575
576* task 的句柄,该句柄可以用于建立task 之间的依赖,或用于在wait 语句中实现同步。
577
578##### 描述
579
580* **C API中的ffrt_task_handle_t需要用户调用`ffrt_task_handle_destroy`显式销毁。**
581* C API中的task_handle_t对象的置空和销毁由用户完成,对同一个ffrt_task_handle_t仅能调用一次`ffrt_task_handle_destroy`,重复对同一个ffrt_task_handle_t调用`ffrt_task_handle_destroy`,其行为是未定义的。
582* 在`ffrt_task_handle_destroy`之后再对ffrt_task_handle_t进行访问,其行为是未定义的。
583
584##### 样例
585
586```{.c}
587#include <stdio.h>
588#include "ffrt.h"
589
590void func0(void* arg)
591{
592    printf("hello ");
593}
594
595void func1(void* arg)
596{
597    (*(int*)arg)++;
598}
599
600void func2(void* arg)
601{
602    printf("world, x = %d\n", *(int*)arg);
603}
604
605void func3(void* arg)
606{
607    printf("handle wait");
608    (*(int*)arg)++;
609}
610
611typedef struct {
612    ffrt_function_header_t header;
613    ffrt_function_t func;
614    ffrt_function_t after_func;
615    void* arg;
616} c_function;
617
618static void ffrt_exec_function_wrapper(void* t)
619{
620    c_function* f = (c_function*)t;
621    if (f->func) {
622        f->func(f->arg);
623    }
624}
625
626static void ffrt_destroy_function_wrapper(void* t)
627{
628    c_function* f = (c_function*)t;
629    if (f->after_func) {
630        f->after_func(f->arg);
631    }
632}
633
634#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
635static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
636    const ffrt_function_t after_func, void* arg)
637{
638    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
639        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
640    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
641    f->header.exec = ffrt_exec_function_wrapper;
642    f->header.destroy = ffrt_destroy_function_wrapper;
643    f->func = func;
644    f->after_func = after_func;
645    f->arg = arg;
646    return (ffrt_function_header_t*)f;
647}
648
649static inline ffrt_task_handle_t ffrt_submit_h_c(ffrt_function_t func, const ffrt_function_t after_func,
650    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
651{
652    return ffrt_submit_h_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
653}
654
655static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
656    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
657{
658    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
659}
660
661
662int main(int narg, char** argv)
663{
664    // handle work with submit
665    ffrt_task_handle_t h = ffrt_submit_h_c(func0, NULL, NULL, NULL, NULL, NULL); // not need some data in this task
666    int x = 1;
667    const std::vector<ffrt_dependence_t> in_deps = {{ffrt_dependence_data, &x}};
668    ffrt_deps_t d2{static_cast<uint32_t>(in_deps.size()), in_deps.data()};
669
670    const std::vector<ffrt_dependence_t> out_deps = {{ffrt_dependence_data, &x}};
671    ffrt_deps_t d1{static_cast<uint32_t>(out_deps.size()), out_deps.data()};
672
673    ffrt_submit_c(func1, NULL, &x, NULL, &d1, NULL);
674    ffrt_submit_c(func2, NULL, &x, &d2, NULL, NULL); // this task depend x and h
675    ffrt_task_handle_destroy(h);
676
677    // handle work with wait
678    ffrt_task_handle_t h2 = ffrt_submit_h_c(func3, NULL, &x, NULL, NULL, NULL);
679
680    const std::vector<ffrt_dependence_t> wait_deps = {{ffrt_dependence_task, h2}};
681    ffrt_deps_t d3{static_cast<uint32_t>(wait_deps.size()), wait_deps.data()};
682    ffrt_wait_deps(&d3);
683    ffrt_task_handle_destroy(h2);
684    printf("x = %d", x);
685    ffrt_wait();
686    return 0;
687}
688```
689
690* 预期的输出为:
691
692```
693hello world, x = 2
694handle wait
695x = 3
696```
697
698
699
700#### ffrt_this_task_get_id
701
702<hr/>
703
704* 返回当前task的id标识,更多使用用于维测(原因是task name可能重名)。
705
706##### 声明
707
708```{.c}
709uint64_t ffrt_this_task_get_id();
710```
711
712##### 参数
713
714* 不涉及。
715
716##### 返回值
717
718* 当前task的id。
719
720##### 描述
721
722* 该接口在task内部调用将返回当前task的id标识,在task外部调用将返回0。
723* 可以基于该接口在task外部调用返回0的特性来区分函数是运行在FFRT 工作线程上还是非FFRT工作线程上。
724* task id为从1开始编码,每提交一个task便增加1,被设计成64bit,即便是每秒百万次提交,也需要292471.2年才会发生翻转。
725
726##### 样例
727
728* 忽略。
729
730
731
732#### ffrt_this_task_update_qos
733
734<hr/>
735
736* 更新当前正在执行的task的优先级。
737
738##### 声明
739
740```{.c}
741int ffrt_this_task_update_qos(ffrt_qos_t qos);
742```
743
744##### 参数
745
746* `qos` 新的优先级。
747
748##### 返回值
749
750* 0表示成功,非0表示失败。
751
752##### 描述
753
754* 该接口对当前task的qos调整会立即生效。
755* 如果新设定的qos与当前的qos不一致,则会block当前task的执行,再按照新的qos恢复执行。
756* 如果新设定的qos与当前的qos一致,则接口会立即返回0,不做任何处理。
757* **如果在非task内部调用该接口,则返回非0值,用户可以选择忽略或其他处理。**
758
759##### 样例
760
761* 忽略。
762
763### 串行队列
764<hr />
765* FFRT提供queue来实现Andorid中类似WorkQueue能力,且在使用得当的情况下将有更好的性能。
766
767#### ffrt_queue_attr_t
768
769##### 声明
770```{.c}
771typedef struct {
772    uint32_t storage[(ffrt_queue_attr_storage_size + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
773} ffrt_queue_attr_t;
774
775int ffrt_queue_attr_init(ffrt_queue_attr_t* attr);
776void ffrt_queue_attr_destroy(ffrt_queue_attr_t* attr);
777```
778
779##### 参数
780
781`attr`
782* 该参数是指向未初始化的ffrt_queue_attr_t。
783
784##### 返回值
785* 若成功返回0,否则返回-1。
786
787##### 描述
788* ffrt_queue_attr_t用于创建ffrt_queue_t且不单独使用,因此必须在创建队列前先创建好队列属性。
789* ffrt_queue_attr_t对象的置空和销毁由用户完成,对同一个ffrt_queue_attr_t仅能调用一次`ffrt_queue_attr_destroy`,重复对同一个ffrt_queue_attr_t调用`ffrt_queue_attr_destroy`,其行为是未定义的。
790* 在`ffrt_queue_attr_destroy`之后再对ffrt_queue_attr_t进行访问,其行为是未定义的。
791
792##### 样例
793参考ffrt_queue_t章节的样例。
794
795#### ffrt_queue_t
796
797##### 声明
798```{.c}
799typedef enum { ffrt_queue_serial, ffrt_queue_max } ffrt_queue_type_t;
800typedef void* ffrt_queue_t;
801
802ffrt_queue_t ffrt_queue_create(ffrt_queue_type_t type, const char* name, const ffrt_queue_attr_t* attr)
803void ffrt_queue_destroy(ffrt_queue_t queue)
804```
805
806##### 参数
807
808`type`
809* 该参数用于描述创建的队列类型。
810
811`name`
812* 该参数用于描述创建队列的名字。
813
814`attr`
815* 该参数用于描述queue的属性,详见ffrt_queue_attr_t章节。
816
817##### 返回值
818* 若成功则返回新创建的队列,否则返回空指针。
819
820##### 描述
821* 提交至该队列的任务将按照顺序执行,如果某个提交的任务中发生阻塞,则无法保证该任务的执行顺序。
822* ffrt_queue_t对象的置空和销毁由用户完成,对同一个ffrt_queue_t仅能调用一次`ffrt_queue_destroy`,重复对同一个ffrt_queue_t调用`ffrt_queue_destroy`,其行为是未定义的。
823* 在`ffrt_queue_destroy`之后再对ffrt_queue_t进行访问,其行为是未定义的。
824
825##### 样例
826```
827#include <stdio.h>
828#include "ffrt.h"
829
830using namespace std;
831
832template<class T>
833struct Function {
834    template<class CT>
835    Function(ffrt_function_header_t h, CT&& c) : header(h), closure(std::forward<CT>(c)) {}
836    ffrt_function_header_t header;
837    T closure;
838};
839
840template<class T>
841void ExecFunctionWrapper(void* t)
842{
843    auto f = reinterpret_cast<Function<std::decay_t<T>>*>(t);
844    f->closure();
845}
846
847template<class T>
848void DestroyFunctionWrapper(void* t)
849{
850    auto f = reinterpret_cast<Function<std::decay_t<T>>*>(t);
851    f->closure = nullptr;
852}
853
854template<class T>
855static inline ffrt_function_header_t* create_function_wrapper(T&& func,
856    ffrt_function_kind_t kind = ffrt_function_kind_general)
857{
858    using function_type = Function<std::decay_t<T>>;
859    auto p = ffrt_alloc_auto_managed_function_storage_base(kind);
860    auto f =
861        new (p)function_type({ ExecFunctionWrapper<T>, DestroyFunctionWrapper<T>, { 0 } }, std::forward<T>(func));
862    return reinterpret_cast<ffrt_function_header_t*>(f);
863}
864
865int main(int narg, char** argv)
866{
867    ffrt_queue_attr_t queue_attr;
868    (void)ffrt_queue_attr_init(&queue_attr);
869    ffrt_queue_t queue_handle = ffrt_queue_create(ffrt_queue_serial, "test_queue", &queue_attr);
870
871    ffrt_queue_submit(queue_handle, create_function_wrapper([]() {printf("Task done.\n");}, ffrt_function_kind_queue), nullptr);
872
873    ffrt_queue_attr_destroy(&queue_attr);
874    ffrt_queue_destroy(queue_handle);
875}
876```
877### 同步原语
878
879#### ffrt_mutex_t
880<hr/>
881* FFRT提供的类似pthread mutex 的性能实现。
882
883##### 声明
884
885```{.c}
886typedef enum {
887    ffrt_error = -1,
888    ffrt_success = 0,
889    ffrt_error_nomem = ENOMEM,
890    ffrt_error_timedout = ETIMEDOUT,
891    ffrt_error_busy = EBUSY,
892    ffrt_error_inval = EINVAL
893} ffrt_error_t;
894
895struct ffrt_mutex_t;
896
897int ffrt_mutex_init(ffrt_mutex_t* mutex, const ffrt_mutexattr_t* attr);
898int ffrt_mutex_lock(ffrt_mutex_t* mutex);
899int ffrt_mutex_unlock(ffrt_mutex_t* mutex);
900int ffrt_mutex_trylock(ffrt_mutex_t* mutex);
901int ffrt_mutex_destroy(ffrt_mutex_t* mutex);
902```
903
904##### 参数
905
906`attr`
907
908* 当前FFRT只支持基础类型的mutex,因此attr必须为空指针。
909
910`mutex`
911
912* 指向所操作的互斥锁的指针。
913
914##### 返回值
915
916* 若成功则为 ffrt_success ,否则发生错误。
917
918##### 描述
919* 该接口只能在FFRT task 内部调用,在FFRT task 外部调用存在未定义的行为。
920* 该功能能够避免pthread传统的pthread_mutex_t 在抢不到锁时陷入内核的问题,在使用得当的条件下将会有更好的性能。
921* **注意:目前暂不支持递归和定时功能。**
922* **注意:C API中的ffrt_mutex_t需要用户调用`ffrt_mutex_init`和`ffrt_mutex_destroy`显式创建和销毁。**
923* **注意:C API中的ffrt_mutex_t对象的置空和销毁由用户完成,对同一个ffrt_mutex_t仅能调用一次`ffrt_mutex_destroy`,重复对同一个ffrt_mutex_t调用`ffrt_mutex_destroy`,其行为是未定义的。**
924* **注意:在`ffrt_mutex_destroy`之后再对ffrt_mutex_t进行访问,其行为是未定义的。**
925
926##### 样例
927
928```{.c}
929#include <stdio.h>
930#include "ffrt.h"
931
932typedef struct {
933    int* sum;
934    ffrt_mutex_t* mtx;
935} tuple;
936
937void func(void* arg)
938{
939    tuple* t = (tuple*)arg;
940
941    int ret = ffrt_mutex_lock(t->mtx);
942    if (ret != ffrt_success) {
943        printf("error\n");
944    }
945    (*t->sum)++;
946    ret = ffrt_mutex_unlock(t->mtx);
947    if (ret != ffrt_success) {
948        printf("error\n");
949    }
950}
951
952typedef struct {
953    ffrt_function_header_t header;
954    ffrt_function_t func;
955    ffrt_function_t after_func;
956    void* arg;
957} c_function;
958
959static void ffrt_exec_function_wrapper(void* t)
960{
961    c_function* f = (c_function*)t;
962    if (f->func) {
963        f->func(f->arg);
964    }
965}
966
967static void ffrt_destroy_function_wrapper(void* t)
968{
969    c_function* f = (c_function*)t;
970    if (f->after_func) {
971        f->after_func(f->arg);
972    }
973}
974
975#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
976static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
977    const ffrt_function_t after_func, void* arg)
978{
979    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
980        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
981    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
982    f->header.exec = ffrt_exec_function_wrapper;
983    f->header.destroy = ffrt_destroy_function_wrapper;
984    f->func = func;
985    f->after_func = after_func;
986    f->arg = arg;
987    return (ffrt_function_header_t*)f;
988}
989
990static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
991    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
992{
993    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
994}
995
996void ffrt_mutex_task()
997{
998    int sum = 0;
999    ffrt_mutex_t mtx;
1000    tuple t = {&sum, &mtx};
1001    int ret = ffrt_mutex_init(&mtx, NULL);
1002    if (ret != ffrt_success) {
1003        printf("error\n");
1004    }
1005    for (int i = 0; i < 10; i++) {
1006        ffrt_submit_c(func, NULL, &t, NULL, NULL, NULL);
1007    }
1008    ffrt_mutex_destroy(&mtx);
1009    ffrt_wait();
1010    printf("sum = %d", sum);
1011}
1012
1013int main(int narg, char** argv)
1014{
1015    int r;
1016    ffrt_submit_c(ffrt_mutex_task, NULL, NULL, NULL, NULL, NULL);
1017    ffrt_wait();
1018    return 0;
1019}
1020```
1021
1022预期输出为:
1023
1024```
1025sum=10
1026```
1027
1028* 该例子为功能示例,实际中并不鼓励这样使用。
1029
1030
1031#### ffrt_cond_t
1032<hr/>
1033
1034* FFRT提供的类似pthread 信号量的性能实现。
1035
1036##### 声明
1037
1038```{.c}
1039typedef enum {
1040    ffrt_error = -1,
1041    ffrt_success = 0,
1042    ffrt_error_nomem = ENOMEM,
1043    ffrt_error_timedout = ETIMEDOUT,
1044    ffrt_error_busy = EBUSY,
1045    ffrt_error_inval = EINVAL
1046} ffrt_error_t;
1047
1048struct ffrt_cond_t;
1049
1050int ffrt_cond_init(ffrt_cond_t* cond, const ffrt_condattr_t* attr);
1051int ffrt_cond_signal(ffrt_cond_t* cond);
1052int ffrt_cond_broadcast(ffrt_cond_t* cond);
1053int ffrt_cond_wait(ffrt_cond_t*cond, ffrt_mutex_t* mutex);
1054int ffrt_cond_timedwait(ffrt_cond_t* cond, ffrt_mutex_t* mutex, const struct timespec* time_point);
1055int ffrt_cond_destroy(ffrt_cond_t* cond);
1056```
1057
1058##### 参数
1059
1060`cond`
1061
1062* 指向所操作的信号量的指针。
1063
1064`attr`
1065
1066* 属性设定,空指针表示使用默认属性。
1067
1068`mutex`
1069
1070* 指向要在阻塞期间解锁的互斥锁的指针。
1071
1072`time_point`
1073
1074* 指向指定等待时限时间的对象的指针。
1075
1076
1077##### 返回值
1078
1079* 若成功则为 ffrt_success,若在锁定互斥前抵达时限则为 ffrt_error_timedout。
1080
1081##### 描述
1082* 该接口只能在FFRT task 内部调用,在FFRT task 外部调用存在未定义的行为。
1083* 该功能能够避免传统的pthread_cond_t在条件不满足时陷入内核的问题,在使用得当的条件下将会有更好的性能。
1084* **注意:C API中的ffrt_cond_t需要用户调用`ffrt_cond_init`和`ffrt_cond_destroy`显式创建和销毁。**
1085* **注意:C API中的ffrt_cond_t对象的置空和销毁由用户完成,对同一个ffrt_cond_t仅能调用一次`ffrt_cond_destroy`,重复对同一个ffrt_cond_t调用`ffrt_cond_destroy`,其行为是未定义的。**
1086* **注意:在`ffrt_cond_destroy`之后再对ffrt_cond_t进行访问,其行为是未定义的。**
1087
1088##### 样例
1089
1090```{.c}
1091#include <stdio.h>
1092#include "ffrt.h"
1093
1094typedef struct {
1095    ffrt_cond_t* cond;
1096    int* a;
1097    ffrt_mutex_t* lock_;
1098} tuple;
1099
1100void func1(void* arg)
1101{
1102    tuple* t = (tuple*)arg;
1103    int ret = ffrt_mutex_lock(t->lock_);
1104    if (ret != ffrt_success) {
1105        printf("error\n");
1106    }
1107    while (*t->a != 1) {
1108        ret = ffrt_cond_wait(t->cond, t->lock_);
1109        if (ret != ffrt_success) {
1110            printf("error\n");
1111        }
1112    }
1113    ret = ffrt_mutex_unlock(t->lock_);
1114    if (ret != ffrt_success) {
1115        printf("error\n");
1116    }
1117    printf("a = %d", *(t->a));
1118}
1119
1120void func2(void* arg)
1121{
1122    tuple* t = (tuple*)arg;
1123    int ret = ffrt_mutex_lock(t->lock_);
1124    if (ret != ffrt_success) {
1125        printf("error\n");
1126    }
1127    *(t->a) = 1;
1128    ret = ffrt_cond_signal(t->cond);
1129    if (ret != ffrt_success) {
1130        printf("error\n");
1131    }
1132    ret = ffrt_mutex_unlock(t->lock_);
1133    if (ret != ffrt_success) {
1134        printf("error\n");
1135    }
1136}
1137
1138typedef struct {
1139    ffrt_function_header_t header;
1140    ffrt_function_t func;
1141    ffrt_function_t after_func;
1142    void* arg;
1143} c_function;
1144
1145static void ffrt_exec_function_wrapper(void* t)
1146{
1147    c_function* f = (c_function*)t;
1148    if (f->func) {
1149        f->func(f->arg);
1150    }
1151}
1152
1153static void ffrt_destroy_function_wrapper(void* t)
1154{
1155    c_function* f = (c_function*)t;
1156    if (f->after_func) {
1157        f->after_func(f->arg);
1158    }
1159}
1160
1161#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
1162static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
1163    const ffrt_function_t after_func, void* arg)
1164{
1165    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
1166        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
1167    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
1168    f->header.exec = ffrt_exec_function_wrapper;
1169    f->header.destroy = ffrt_destroy_function_wrapper;
1170    f->func = func;
1171    f->after_func = after_func;
1172    f->arg = arg;
1173    return (ffrt_function_header_t*)f;
1174}
1175
1176static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
1177    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
1178{
1179    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
1180}
1181
1182void ffrt_cv_task()
1183{
1184    ffrt_cond_t cond;
1185    int ret = ffrt_cond_init(&cond, NULL);
1186    if (ret != ffrt_success) {
1187        printf("error\n");
1188    }
1189    int a = 0;
1190    ffrt_mutex_t lock_;
1191    tuple t = {&cond, &a, &lock_};
1192    ret = ffrt_mutex_init(&lock_, NULL);
1193    if (ret != ffrt_success) {
1194        printf("error\n");
1195    }
1196    ffrt_submit_c(func1, NULL, &t, NULL, NULL, NULL);
1197    ffrt_submit_c(func2, NULL, &t, NULL, NULL, NULL);
1198    ffrt_wait();
1199    ffrt_cond_destroy(&cond);
1200    ffrt_mutex_destroy(&lock_);
1201}
1202
1203int main(int narg, char** argv)
1204{
1205    ffrt_submit_c(ffrt_cv_task, NULL, NULL, NULL, NULL, NULL);
1206    ffrt_wait();
1207    return 0;
1208}
1209```
1210
1211预期输出为:
1212
1213```
1214a=1
1215```
1216
1217* 该例子为功能示例,实际中并不鼓励这样使用。
1218
1219### 杂项
1220
1221#### ffrt_usleep
1222
1223<hr/>
1224* FFRT提供的类似C11 sleep和linux usleep的性能实现。
1225
1226##### 声明
1227
1228```{.c}
1229int ffrt_usleep(uint64_t usec);
1230```
1231
1232##### 参数
1233
1234`usec`
1235
1236* 睡眠的us数。
1237
1238##### 返回值
1239
1240* 不涉及。
1241
1242##### 描述
1243* 该接口只能在FFRT task 内部调用,在FFRT task 外部调用存在未定义的行为。
1244* 该功能能够避免传统的sleep 睡眠时陷入内核的问题,在使用得当的条件下将会有更好的性能。
1245
1246##### 样例
1247
1248```{.c}
1249#include <time.h>
1250#include <stdio.h>
1251#include "ffrt.h"
1252
1253void func(void* arg)
1254{
1255    printf("Time: %s", ctime(&(time_t){time(NULL)}));
1256    ffrt_usleep(2000000); // 睡眠 2 秒
1257    printf("Time: %s", ctime(&(time_t){time(NULL)}));
1258}
1259
1260typedef struct {
1261    ffrt_function_header_t header;
1262    ffrt_function_t func;
1263    ffrt_function_t after_func;
1264    void* arg;
1265} c_function;
1266
1267static void ffrt_exec_function_wrapper(void* t)
1268{
1269    c_function* f = (c_function*)t;
1270    if (f->func) {
1271        f->func(f->arg);
1272    }
1273}
1274
1275static void ffrt_destroy_function_wrapper(void* t)
1276{
1277    c_function* f = (c_function*)t;
1278    if (f->after_func) {
1279        f->after_func(f->arg);
1280    }
1281}
1282
1283#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
1284static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
1285    const ffrt_function_t after_func, void* arg)
1286{
1287    FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size,
1288        size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
1289    c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general);
1290    f->header.exec = ffrt_exec_function_wrapper;
1291    f->header.destroy = ffrt_destroy_function_wrapper;
1292    f->func = func;
1293    f->after_func = after_func;
1294    f->arg = arg;
1295    return (ffrt_function_header_t*)f;
1296}
1297
1298static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func,
1299    void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr)
1300{
1301    ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr);
1302}
1303
1304int main(int narg, char** argv)
1305{
1306    ffrt_submit_c(func, NULL, NULL, NULL, NULL, NULL);
1307    ffrt_wait();
1308    return 0;
1309}
1310```
1311
1312#### ffrt_yield
1313<hr/>
1314* 当前task 主动让出CPU 执行资源,让其他可以被执行的task 先执行,如果没有其他可被执行的task,yield 无效。
1315
1316##### 声明
1317
1318```{.c}
1319void ffrt_yield();
1320```
1321
1322##### 参数
1323
1324* 不涉及。
1325
1326##### 返回值
1327
1328* 不涉及。
1329
1330##### 描述
1331* 该接口只能在FFRT task 内部调用,在FFRT task 外部调用存在未定义的行为。
1332* 此函数的确切行为取决于实现,特别是使用中的FFRT 调度程序的机制和系统状态。
1333
1334##### 样例
1335
1336* 省略。
1337
1338
1339## 开发步骤
1340
1341以下步骤描述了如何使用`FFRT`提供的Native API接口,创建并行任务和串行队列任务以及销毁相应资源。
1342
1343**添加动态链接库**
1344
1345CMakeLists.txt中添加以下lib:
1346```txt
1347libffrt.z.so
1348```
1349
1350**头文件**
1351```c++
1352#include "ffrt/task.h"
1353#include "ffrt/type_def.h"
1354#include "ffrt/condition_variable.h"
1355#include "ffrt/mutex.h"
1356#include "ffrt/queue.h"
1357#include "ffrt/sleep.h"
1358```
1359
13601. **首先需要对执行的函数进行封装**。
1361    ```c++
1362    // 第一种使用模板,支持C++
1363    template<class T>
1364    struct Function {
1365        template<class CT>
1366        Function(ffrt_function_header_t h, CT&& c) : header(h), closure(std::forward<CT>(c)) {}
1367        ffrt_function_header_t header;
1368        T closure;
1369    };
1370
1371    template<class T>
1372    void ExecFunctionWrapper(void* t)
1373    {
1374        auto f = reinterpret_cast<Function<std::decay_t<T>>*>(t);
1375        f->closure();
1376    }
1377
1378    template<class T>
1379    void DestroyFunctionWrapper(void* t)
1380    {
1381        auto f = reinterpret_cast<Function<std::decay_t<T>>*>(t);
1382        f->closure = nullptr;
1383    }
1384
1385    template<class T>
1386    static inline ffrt_function_header_t* create_function_wrapper(T&& func,
1387        ffrt_function_kind_t kind = ffrt_function_kind_general)
1388    {
1389        using function_type = Function<std::decay_t<T>>;
1390        auto p = ffrt_alloc_auto_managed_function_storage_base(kind);
1391        auto f =
1392            new (p)function_type({ ExecFunctionWrapper<T>, DestroyFunctionWrapper<T>, { 0 } }, std::forward<T>(func));
1393        return reinterpret_cast<ffrt_function_header_t*>(f);
1394    }
1395
1396    // 第二种创建方式
1397    typedef struct {
1398        ffrt_function_header_t header;
1399        ffrt_function_t func;
1400        ffrt_function_t after_func;
1401        void* arg;
1402    } CFunction;
1403
1404    static void FfrtExecFunctionWrapper(void* t)
1405    {
1406        CFunction* f = static_cast<CFunction*>(t);
1407        if (f->func) {
1408            f->func(f->arg);
1409        }
1410    }
1411
1412    static void FfrtDestroyFunctionWrapper(void* t)
1413    {
1414        CFunction* f = static_cast<CFunction*>(t);
1415        if (f->after_func) {
1416            f->after_func(f->arg);
1417        }
1418    }
1419
1420    #define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1])
1421    static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func,
1422        const ffrt_function_t after_func, void* arg, ffrt_function_kind_t kind_t = ffrt_function_kind_general)
1423    {
1424        FFRT_STATIC_ASSERT(sizeof(CFunction) <= ffrt_auto_managed_function_storage_size,
1425            size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size);
1426        CFunction* f = static_cast<CFunction*>(ffrt_alloc_auto_managed_function_storage_base(kind_t));
1427        f->header.exec = FfrtExecFunctionWrapper;
1428        f->header.destroy = FfrtDestroyFunctionWrapper;
1429        f->func = func;
1430        f->after_func = after_func;
1431        f->arg = arg;
1432        return reinterpret_cast<ffrt_function_header_t*>(f);
1433    }
1434
1435    // 样例:待提交执行的函数
1436    void OnePlusForTest(void* arg)
1437    {
1438        (*static_cast<int*>(arg)) += 1;
1439    }
1440    ```
1441
14422. **设置task属性值**。
1443
1444    用户提交任务时可以设置任务属性,包括qos优先级,名称等,具体可参考接口文档。
1445    ```c++
1446    // ******初始化并行任务属性******
1447    ffrt_task_attr_t attr;
1448    ffrt_task_attr_init(&attr);
1449
1450    // ******创建串行队列******
1451
1452    // 创建串行队列的属性
1453    ffrt_queue_attr_t queue_attr;
1454    // 创建串行队列的handle
1455    ffrt_queue_t queue_handle;
1456
1457    // 初始化队列属性
1458    (void)ffrt_queue_attr_init(&queue_attr);
1459
1460    // 如有需要,设置指定优先级
1461    ffrt_queue_attr_set_qos(&queue_attr, static_cast<ffrt_qos_t>(ffrt_qos_inherit));
1462    // 如有需要,设置超时时间(ms)
1463    ffrt_queue_attr_set_timeout(&queue_attr, 10000);
1464    // 如有需要,设置超时回调
1465    int x = 0;
1466    ffrt_queue_attr_set_callback(&queue_attr, ffrt_create_function_wrapper(OnePlusForTest, NULL, &x,
1467        ffrt_function_kind_queue));
1468
1469    // 基于属性,初始化队列
1470    queue_handle = ffrt_queue_create(ffrt_queue_serial, "test_queue", &queue_attr);
1471    ```
1472
14733. **提交任务**。
1474    ```c++
1475    int a = 0;
1476    // ******并行任务******
1477    // 提交不带handle返回值的并行任务
1478    ffrt_submit_base(ffrt_create_function_wrapper(OnePlusForTest, NULL, &a), NULL, NULL, &attr);
1479    // 提交带handle返回值的并行任务
1480    ffrt_task_handle_t task = ffrt_submit_h_base(
1481        ffrt_create_function_wrapper(OnePlusForTest, NULL, &a), NULL, NULL, &attr);
1482
1483    // ******串行任务******
1484    // 提交不返回handle的串行队列任务
1485    ffrt_queue_submit(queue_handle, ffrt_create_function_wrapper(OnePlusForTest, nullptr, &a,
1486        ffrt_function_kind_queue), nullptr);
1487    // 提交带handle的串行队列任务
1488    ffrt_task_handle_t handle = ffrt_queue_submit_h(queue_handle,
1489        ffrt_create_function_wrapper(OnePlusForTest, nullptr, &a, ffrt_function_kind_queue), nullptr);
1490
1491    // 如果需要等待执行结果,则调用wait
1492    const std::vector<ffrt_dependence_t> wait_deps = {{ffrt_dependence_task, task}};
1493    ffrt_deps_t wait{static_cast<uint32_t>(wait_deps.size()), wait_deps.data()};
1494    ffrt_wait_deps(&wait);
1495
1496    ffrt_queue_wait(handle);
1497    ```
1498
14994. **任务提交完成后销毁相应资源**。
1500    ```c++
1501    // ******销毁并行任务******
1502    ffrt_task_attr_destroy(&attr);
1503    ffrt_task_handle_destroy(task);
1504
1505    // ******销毁串行队列任务******
1506    // 先销毁任务handle,再销毁队列
1507    ffrt_queue_attr_destroy(&queue_attr);
1508    ffrt_task_handle_destroy(handle);
1509    ffrt_queue_destroy(queue_handle);
1510    ```
1511
1512## 使用建议
1513
1514### 建议1: 函数化
1515
1516**基本思想:计算过程函数化**
1517
1518* 程序过程各步骤以函数封装表达,函数满足类纯函数特性。
1519* 无全局数据访问。
1520* 无内部状态保留。
1521* 通过ffrt_submit_base()接口以异步任务方式提交函数执行。
1522* 将函数访问的数据对象以及访问方式在ffrt_submit_base()接口中的in_deps/out_deps参数表达。
1523* 程序员通过inDeps/outDeps参数表达任务间依赖关系以保证程序执行的正确性。
1524
1525> 做到纯函数的好处在于:1. 能够最大化挖掘并行度,2.避免DataRace和锁的问题。
1526
1527
1528
1529**在实际中,可以根据场景放松纯函数的约束,但前提是:**
1530
1531* 确定添加的in_deps/out_deps可确保程序正确执行。
1532* 通过FFRT提供的锁机制保护对全局变量的访问。
1533
1534
1535### 建议2: 使用FFRT提供的替代API
1536
1537* 禁止在FFRT任务中使用系统线程库API创建线程,使用submit提交任务。
1538* 使用FFRT提供的锁,条件变量,睡眠,IO等API代替系统线程库API。
1539  * 使用系统线程库API可能造成工作线程阻塞,引起额外性能开销。
1540
1541
1542
1543### 建议3: Deadline机制
1544
1545* **必须用于具备周期/重复执行特征的处理流程。**
1546* 在有明确时间约束和性能关键的处理流程中使用,避免滥用。
1547* 在相对大颗粒度的处理流程中使用,例如具有16.6ms时间约束的帧处理流程。
1548
1549
1550
1551### 建议4: 从线程模型迁移
1552
1553* 创建线程替代为创建FFRT任务。
1554  * 线程从逻辑上类似无in_deps的任务。
1555* 识别线程间的依赖关系,并将其表达在任务的依赖关系in_deps/out_deps上。
1556* 线程内计算过程分解为异步任务调用。
1557* 通过任务依赖关系和锁机制避免并发任务数据竞争问题。
1558
1559
1560
1561### 建议5: 推荐使用c++接口
1562
1563* FFRT的c++接口是基于C接口实现,在使用API接口时可以手动添加C++相关头文件后配套使用。
1564* 相关C++接口下载参考:
1565- [FFRT c++接口](https://gitee.com/wangyulie/resourceschedule_ffrt/tree/master/interfaces/kits)
1566
1567
1568
1569
1570
1571## 已知限制
1572
1573
1574### C API中初始化ffrt对象后,对象的置空与销毁由用户负责
1575
1576* 为保证较高的性能,ffrt的C API中内部不包含对对象的销毁状态的标记,用户需要合理地进行资源的释放,重复调用各个对象的destroy操作,其结果是未定义的。
1577* 错误示例1,重复调用destroy可能造成不可预知的数据损坏。
1578
1579```{.c}
1580#include "ffrt.h"
1581void abnormal_case_1()
1582{
1583    ffrt_task_handle_t h = ffrt_submit_h_base([](){printf("Test task running...\n");}, NULL, NULL, NULL, NULL, NULL);
1584    ...
1585    ffrt_task_handle_destroy(h);
1586    ffrt_task_handle_destroy(h); // double free
1587}
1588```
1589
1590* 错误示例2,未调用destroy会造成内存泄漏
1591
1592```{.c}
1593#include "ffrt.h"
1594void abnormal_case_2()
1595{
1596    ffrt_task_handle_t h = ffrt_submit_h_base([](){printf("Test task running...\n");}, NULL, NULL, NULL, NULL, NULL);
1597    ...
1598    // memory leak
1599}
1600```
1601
1602* 建议示例,仅调用一次destroy,如有必要可进行置空
1603
1604```{.c}
1605#include "ffrt.h"
1606void normal_case()
1607{
1608    ffrt_task_handle_t h = ffrt_submit_h_base([](){printf("Test task running...\n");}, NULL, NULL, NULL, NULL, NULL);
1609    ...
1610    ffrt_task_handle_destroy(h);
1611    h = nullptr; // if necessary
1612}
1613```
1614