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