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_queue_attr_set_max_concurrency(ffrt_queue_attr_t* attr, const int max_concurrency) | 设置并行队列最大并发度。 | 39| ffrt_queue_attr_get_max_concurrency(ffrt_queue_attr_t* attr) | 获取并行队列最大并发度。 | 40| ffrt_get_main_queue() | 获取主线程队列。 | 41| ffrt_get_current_queue() | 获取Worker线程队列。 | 42| ffrt_usleep(uint64_t usec) | 延迟usec微秒。 | 43| ffrt_yield(void) | 当前任务主动放权,让其他任务有机会调度执行。 | 44| ffrt_task_attr_init(ffrt_task_attr_t* attr) | 初始化任务属性。 | 45| ffrt_task_attr_set_name(ffrt_task_attr_t* attr, const char* name) | 设置任务名字。 | 46| ffrt_task_attr_get_name(const ffrt_task_attr_t* attr) | 获取任务名字。 | 47| ffrt_task_attr_destroy(ffrt_task_attr_t* attr) | 销毁任务属性。 | 48| ffrt_task_attr_set_qos(ffrt_task_attr_t* attr, ffrt_qos_t qos) | 设置任务qos。 | 49| ffrt_task_attr_get_qos(const ffrt_task_attr_t* attr) | 获取任务qos。 | 50| ffrt_task_attr_set_delay(ffrt_task_attr_t* attr, uint64_t delay_us) | 设置任务延迟时间。 | 51| ffrt_task_attr_get_delay(const ffrt_task_attr_t* attr) | 获取任务延迟时间。 | 52| ffrt_task_attr_set_queue_priority(ffrt_task_attr_t* attr, ffrt_queue_priority_t priority) | 设置并行队列任务优先级。 | 53| ffrt_task_attr_get_queue_priority(const ffrt_task_attr_t* attr) | 获取并行队列任务优先级。 | 54| ffrt_this_task_get_qos() | 获取任务qos。 | 55| ffrt_this_task_update_qos(ffrt_qos_t qos) | 更新任务qos。 | 56| ffrt_this_task_get_id(void) | 获取任务id。 | 57| ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_t kind) | 申请函数执行结构的内存。 | 58| ffrt_submit_base(ffrt_function_header_t* f, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr) | 提交任务调度执行。 | 59| ffrt_submit_h_base(ffrt_function_header_t* f, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr) | 提交任务调度执行并返回任务句柄。 | 60| ffrt_task_handle_destroy(ffrt_task_handle_t handle) | 销毁任务句柄。 | 61| ffrt_skip(ffrt_task_handle_t handle) | 跳过指定任务。 | 62| ffrt_wait_deps(const ffrt_deps_t* deps) | 等待依赖的任务完成,当前任务开始执行。 | 63| ffrt_loop_create(ffrt_queue_t queue) | 创建loop对象。 | 64| ffrt_loop_destroy(ffrt_loop_t loop) | 销毁loop对象。 | 65| ffrt_loop_run(ffrt_loop_t loop) | 启动loop循环。 | 66| ffrt_loop_stop(ffrt_loop_t loop) | 停止loop循环。 | 67| ffrt_loop_epoll_ctl(ffrt_loop_t loop, int op, int fd, uint32_t events, void* data, ffrt_poller_cb cb) | 管理LOOP上的监听事件。 | 68| ffrt_loop_timer_start(ffrt_loop_t loop, uint64_t timeout, void* data, ffrt_timer_cb cb, bool repeat) | 在LOOP上启动一个定时器。 | 69| ffrt_loop_timer_stop(ffrt_loop_t loop, ffrt_timer_t handle) | 在LOOP上停止定时器。 | 70| ffrt_timer_start(ffrt_qos_t qos, uint64_t timeout, void* data, ffrt_timer_cb cb, bool repeat) | 启动timer定时器。 | 71| ffrt_timer_stop(ffrt_qos_t qos, ffrt_timer_t handle); | 停止timer定时器。 | 72 73## 函数介绍 74 75 76### 任务管理 77 78#### ffrt_submit_base 79 80* 该接口为ffrt动态库的导出接口,基于此可以封装出C API ffrt_submit,满足二进制兼容。 81 82##### 声明 83 84```{.c} 85const int ffrt_auto_managed_function_storage_size = 64 + sizeof(ffrt_function_header_t); 86typedef enum { 87 ffrt_function_kind_general, 88 ffrt_function_kind_queue 89} ffrt_function_kind_t; 90 91void* ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_t kind); 92 93typedef void(*ffrt_function_t)(void*); 94typedef struct { 95 ffrt_function_t exec; 96 ffrt_function_t destroy; 97 uint64_t reserve[2]; 98} ffrt_function_header_t; 99 100void ffrt_submit_base(ffrt_function_header_t* func, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr); 101``` 102 103##### 参数 104 105`kind` 106 107* function子类型,用于优化内部数据结构,默认使用ffrt_function_kind_general类型。 108 109`func` 110 111* CPU Function的指针,该指针执行的数据结构,按照`ffrt_function_header_t`定义的描述了该CPU Task如何执行和销毁的函数指针,FFRT通过这两个函数指针完成Task的执行和销毁。 112 113`in_deps` 114 115* 该参数是可选的。 116* 该参数用于描述该任务的输入依赖,FFRT 通过数据的虚拟地址作为数据的Signature 来建立依赖。 117 118`out_deps` 119 120* 该参数是可选的。 121* 该参数用于描述该任务的输出依赖。 122* `注意`:该依赖值本质上是一个数值,ffrt没办法区分该值是合理的还是不合理的,会假定输入的值是合理的进行处理;但不建议采用NULL,1, 2 等值来建立依赖关系,建议采用实际的内存地址,因为前者使用不当会建立起不必要的依赖,影响并发。 123 124`attr` 125 126* 该参数是可选的。 127* 该参数用于描述Task 的属性,比如qos 等,详见 [ffrt_task_attr_t](#ffrt_task_attr_t)章节。 128 129##### 返回值 130 131* 不涉及。 132 133##### 描述 134* 建议用户对ffrt_submit_base进行封装后调用,具体可参考样例。 135* **ffrt_submit_base作为底层能力,使用时需要满足以下限制:** 136 * ffrt_submit_base入参中的func指针只能通过ffrt_alloc_auto_managed_function_storage_base申请,且二者的调用需一一对应。 137 * ffrt_alloc_auto_managed_function_storage_base申请的内存为ffrt_auto_managed_function_storage_size字节,其生命周期归ffrt管理,在该task结束时,由FFRT自动释放,用户无需释放。 138* ffrt_function_header_t 中定义了两个函数指针: 139 * exec:用于描述该Task如何被执行,当FFRT需要执行该Task时由FFRT调用。 140 * destroy:用于描述该Task如何被销毁,当FFRT需要销毁该Task时由FFRT调用。 141 142##### 样例 143 144 145```{.c} 146template<class T> 147struct function { 148 template<class CT> 149 function(ffrt_function_header_t h, CT&& c) : header(h), closure(std::forward<CT>(c)) {} 150 ffrt_function_header_t header; 151 T closure; 152}; 153 154template<class T> 155void exec_function_wrapper(void* t) 156{ 157 auto f = (function<std::decay_t<T>>*)t; 158 f->closure(); 159} 160 161template<class T> 162void destroy_function_wrapper(void* t) 163{ 164 auto f = (function<std::decay_t<T>>*)t; 165 f->closure = nullptr; 166} 167 168template<class T> 169inline ffrt_function_header_t* create_function_wrapper(T&& func) 170{ 171 using function_type = function<std::decay_t<T>>; 172 static_assert(sizeof(function_type) <= ffrt_auto_managed_function_storage_size, 173 "size of function must be less than ffrt_auto_managed_function_storage_size"); 174 175 auto p = ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general); 176 auto f = new (p) function_type( 177 {exec_function_wrapper<T>, destroy_function_wrapper<T>}, 178 std::forward<T>(func)); 179 return (ffrt_function_header_t*)f; 180} 181 182static inline void submit(std::function<void()>&& func) 183{ 184 return ffrt_submit_base(create_function_wrapper(std::move(func)), NULL, NULL, NULL); 185} 186``` 187 188#### ffrt_wait 189 190<hr/> 191* 同步等待,与ffrt_submit_base 配合使用。 192* 等待指定的数据被生产完成,或等待当前任务的所有子任务完成,在不满足条件之前,当前的执行上下文被suspend,在满足条件后恢复执行。 193 194##### 声明 195 196```{.c} 197void ffrt_wait_deps(ffrt_deps_t* deps); 198void ffrt_wait(); 199``` 200 201##### 参数 202 203`deps` 204 205* 需要等待被生产完成的数据的虚拟地址,这些地址可能作为某些任务在submit 时的out_deps,该依赖的生成见ffrt_deps_t章节,空指针表示无依赖。 206 207##### 返回值 208 209* 不涉及。 210 211##### 描述 212* ffrt_wait_deps(deps) 用于等待deps指代的数据被生产完成才能执行后面的代码。 213* ffrt_wait() 用于等待当前上下文提交的所有子任务(`注意:不包括孙任务和下级子任务`)都完成才能执行后面的代码。 214* 该接口支持在FFRT task 内部调用,也支持在FFRT task 外部调用。 215* 在FFRT task 外部调用的wait 是OS 能够感知的等待,相对于FFRT task 内部调用的wait 是更加昂贵的,因此我们希望尽可能让更多的wait 发生在FFRT task 内部 ,而不是FFRT task 外部。 216 217##### 样例 218 219**recursive fibonacci** 220 221串行版的fibonacci 可以实现为: 222 223```{.c} 224#include <stdio.h> 225 226void fib(int x, int* y) { 227 if (x <= 1) { 228 *y = x; 229 } else { 230 int y1, y2; 231 fib(x - 1, &y1); 232 fib(x - 2, &y2); 233 *y = y1 + y2; 234 } 235} 236int main(int narg, char** argv) 237{ 238 int r; 239 fib(10, &r); 240 printf("fibonacci 10: %d\n", r); 241 return 0; 242} 243``` 244 245若要使用 FFRT 实现并行(注,对于单纯的fibonacci,单个 Task 的计算量极小,不具有并行加速的意义,但这种调用pattern 对并行编程模型的灵活性考验是非常高的),其中1种可行的实现为: 246 247```{.c} 248#include <stdio.h> 249#include "ffrt.h" //包含所有ffrt涉及的头文件 250 251typedef struct { 252 int x; 253 int* y; 254} fib_ffrt_s; 255 256typedef struct { 257 ffrt_function_header_t header; 258 ffrt_function_t func; 259 ffrt_function_t after_func; 260 void* arg; 261} c_function; 262 263static void ffrt_exec_function_wrapper(void* t) 264{ 265 c_function* f = (c_function*)t; 266 if (f->func) { 267 f->func(f->arg); 268 } 269} 270 271static void ffrt_destroy_function_wrapper(void* t) 272{ 273 c_function* f = (c_function*)t; 274 if (f->after_func) { 275 f->after_func(f->arg); 276 } 277} 278 279#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1]) 280static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func, 281 const ffrt_function_t after_func, void* arg) 282{ 283 FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size, 284 size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size); 285 c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general); 286 f->header.exec = ffrt_exec_function_wrapper; 287 f->header.destroy = ffrt_destroy_function_wrapper; 288 f->func = func; 289 f->after_func = after_func; 290 f->arg = arg; 291 return (ffrt_function_header_t*)f; 292} 293 294static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func, 295 void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr) 296{ 297 ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr); 298} 299 300void fib_ffrt(void* arg) 301{ 302 fib_ffrt_s* p = (fib_ffrt_s*)arg; 303 int x = p->x; 304 int* y = p->y; 305 306 if (x <= 1) { 307 *y = x; 308 } else { 309 int y1, y2; 310 fib_ffrt_s s1 = {x - 1, &y1}; 311 fib_ffrt_s s2 = {x - 2, &y2}; 312 const std::vector<ffrt_dependence_t> dx_deps = {{ffrt_dependence_data, &x}}; 313 ffrt_deps_t dx{static_cast<uint32_t>(dx_deps.size()), dx_deps.data()}; 314 const std::vector<ffrt_dependence_t> dy1_deps = {{ffrt_dependence_data, &y1}}; 315 ffrt_deps_t dy1{static_cast<uint32_t>(dy1_deps.size()), dy1_deps.data()}; 316 const std::vector<ffrt_dependence_t> dy2_deps = {{ffrt_dependence_data, &y2}}; 317 ffrt_deps_t dy2{static_cast<uint32_t>(dy2_deps.size()), dy2_deps.data()}; 318 const std::vector<ffrt_dependence_t> dy12_deps = {{ffrt_dependence_data, &y1}, {ffrt_dependence_data, &y2}}; 319 ffrt_deps_t dy12{static_cast<uint32_t>(dy12_deps.size()), dy12_deps.data()}; 320 ffrt_submit_c(fib_ffrt, NULL, &s1, &dx, &dy1, NULL); 321 ffrt_submit_c(fib_ffrt, NULL, &s2, &dx, &dy2, NULL); 322 ffrt_wait_deps(&dy12); 323 *y = y1 + y2; 324 } 325} 326 327int main(int narg, char** argv) 328{ 329 int r; 330 fib_ffrt_s s = {10, &r}; 331 const std::vector<ffrt_dependence_t> dr_deps = {{ffrt_dependence_data, &r}}; 332 ffrt_deps_t dr{static_cast<uint32_t>(dr_deps.size()), dr_deps.data()}; 333 ffrt_submit_c(fib_ffrt, NULL, &s, NULL, &dr, NULL); 334 ffrt_wait_deps(&dr); 335 printf("fibonacci 10: %d\n", r); 336 return 0; 337} 338``` 339 340`解析`: 341 3421) 将fibonacci (x-1)和fibonacci (x-2) 作为2个Task 提交给FFRT,在两个Task 完成之后将结果累加; 343 3442) 虽然单个Task 只能拆分成2个SubTask 但是子Task 可以继续拆分,因此,整个计算图的并行度是非常高的,Task 之间在FFRT 内部形成了一颗调用树; 345 346<img src="figures/ffrtfigure2.png" style="zoom:100%" /> 347 348> 以上实现,因为需要用户显式管理数据生命周期和函数入参打包两个因素,所以使得代码实现异常复杂。 349 350 351 352#### ffrt_deps_t 353 354* C API中对依赖数组的抽象,逻辑上等同于C++ API中的`std::vector<void*>` 355 356##### 声明 357 358```{.c} 359typedef enum { 360 ffrt_dependence_data, 361 ffrt_dependence_task, 362} ffrt_dependence_type_t; 363 364typedef struct { 365 ffrt_dependence_type_t type; 366 const void* ptr; 367} ffrt_dependence_t; 368 369typedef struct { 370 uint32_t len; 371 const ffrt_dependence_t* items; 372} ffrt_deps_t; 373``` 374 375##### 参数 376 377`len` 378 379* 所依赖的Signature的个数,取值大于等于0。 380 381`item` 382 383* len个Signature的起始地址指针。 384 385`type` 386 387* 当前依赖为数据依赖还是任务依赖。 388 389`ptr` 390 391* 所依赖对应Signature内容的实际地址。 392 393##### 返回值 394 395* 不涉及。 396 397##### 描述 398 399* item为len个Signature的起始指针,该指针可以指向堆空间,也可以指向栈空间,但是要求分配的空间大于等于len * sizeof(ffrt_dependence_t)。 400 401##### 样例 402 403* 创建数据依赖或者任务依赖: 404 405```{.c} 406// 创建数据依赖的ffrt_deps_t 407int x = 0; 408const std::vector<ffrt_dependence_t> in_deps = {{ffrt_dependence_data, &x}}; 409ffrt_deps_t in{static_cast<uint32_t>(in_deps.size()), in_deps.data()}; 410 411// 提交某个返回handle任务 412ffrt_task_handle_t task = ffrt_submit_h_base( 413 ffrt_create_function_wrapper(OnePlusForTest, NULL, &a), NULL, NULL, &attr); 414// 创建任务依赖的ffrt_deps_t 415const std::vector<ffrt_dependence_t> wait_deps = {{ffrt_dependence_task, task}}; 416ffrt_deps_t wait{static_cast<uint32_t>(wait_deps.size()), wait_deps.data()}; 417``` 418 419#### ffrt_task_attr_t 420 421<hr/> 422* 定义task 的属性的辅助类,与ffrt_submit_base 配合使用。 423 424##### 声明 425 426```{.c} 427typedef enum { 428 ffrt_qos_inherent = -1, 429 ffrt_qos_background, 430 ffrt_qos_utility, 431 ffrt_qos_default, 432 ffrt_qos_user_initiated, 433} ffrt_qos_default_t; 434 435typedef int ffrt_qos_t; 436 437typedef struct { 438 uint32_t storage[(ffrt_task_attr_storage_size + sizeof(uint32_t) - 1) / sizeof(uint32_t)]; 439} ffrt_task_attr_t; 440typedef void* ffrt_task_handle_t; 441 442int ffrt_task_attr_init(ffrt_task_attr_t* attr); 443void ffrt_task_attr_destroy(ffrt_task_attr_t* attr); 444void ffrt_task_attr_set_qos(ffrt_task_attr_t* attr, ffrt_qos_t qos); 445ffrt_qos_t ffrt_task_attr_get_qos(const ffrt_task_attr_t* attr); 446void ffrt_task_attr_set_name(ffrt_task_attr_t* attr, const char* name); 447const char* ffrt_task_attr_get_name(const ffrt_task_attr_t* attr); 448void ffrt_task_attr_set_delay(ffrt_task_attr_t* attr, uint64_t delay_us); 449uint64_t ffrt_task_attr_get_delay(const ffrt_task_attr_t* attr); 450``` 451 452##### 参数 453 454`attr` 455 456* 创建的tasks属性的句柄。 457 458`qos` 459 460* qos 设定的枚举类型。 461* inherent 是一个qos 设定策略,代表即将ffrt_submit 的task 的qos 继承当前task 的qos。 462 463`delay_us` 464 465* 任务延迟执行的时间,单位为us。 466 467##### 返回值 468 469* 不涉及。 470 471##### 描述 472* `attr`所传递的内容会在ffrt_submit内部完成取存,ffrt_submit返回后用户即可销毁。 473* 约定: 474 * 在submit 时,如果不通过task_attr 设定qos,那么默认该提交的task的qos 为`ffrt_qos_default`。 475 * 在submit 时,如果通过task_attr 设定qos 为`ffrt_qos_inherent`,表示将该提交的task 的qos 与当前task 的qos 相同,在FFRT task 外部提交的属性为`ffrt_qos_inherent` 的task,其qos 为`ffrt_qos_default`。 476 * 其他情况下,该提交的task 的qos 被设定为指定的值。 477* ffrt_task_attr_t对象的置空和销毁由用户完成,对同一个ffrt_task_attr_t仅能调用一次`ffrt_task_attr_destroy`,重复对同一个ffrt_task_attr_t调用`ffrt_task_attr_destroy`,其行为是未定义的。 478* 在`ffrt_task_attr_destroy`之后再对task_attr进行访问,其行为是未定义的。 479 480##### 样例 481 482* 提交一个qos 级别为background 的任务: 483 484```{.c} 485#include <stdio.h> 486#include "ffrt.h" 487 488void my_print(void* arg) 489{ 490 printf("hello ffrt\n"); 491} 492 493typedef struct { 494 ffrt_function_header_t header; 495 ffrt_function_t func; 496 ffrt_function_t after_func; 497 void* arg; 498} c_function; 499 500static void ffrt_exec_function_wrapper(void* t) 501{ 502 c_function* f = (c_function*)t; 503 if (f->func) { 504 f->func(f->arg); 505 } 506} 507 508static void ffrt_destroy_function_wrapper(void* t) 509{ 510 c_function* f = (c_function*)t; 511 if (f->after_func) { 512 f->after_func(f->arg); 513 } 514} 515 516#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1]) 517static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func, 518 const ffrt_function_t after_func, void* arg) 519{ 520 FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size, 521 size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size); 522 c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general); 523 f->header.exec = ffrt_exec_function_wrapper; 524 f->header.destroy = ffrt_destroy_function_wrapper; 525 f->func = func; 526 f->after_func = after_func; 527 f->arg = arg; 528 return (ffrt_function_header_t*)f; 529} 530 531static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func, 532 void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr) 533{ 534 ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr); 535} 536 537int main(int narg, char** argv) 538{ 539 ffrt_task_attr_t attr; 540 ffrt_task_attr_init(&attr); 541 ffrt_task_attr_set_qos(&attr, ffrt_qos_background); 542 ffrt_task_attr_set_delay(&attr, 10000); 543 ffrt_submit_c(my_print, NULL, NULL, NULL, NULL, &attr); 544 ffrt_task_attr_destroy(&attr); 545 ffrt_wait(); 546 return 0; 547} 548``` 549 550#### ffrt_submit_h_base 551 552<hr/> 553 554* 向调度器提交一个task,与ffrt_submit_base 的差别在于返回task 的句柄,该句柄可以用于建立task 之间的依赖,或用于在wait 语句中实现同步。 555 556##### 声明 557 558```{.c} 559typedef void* ffrt_task_handle_t; 560 561ffrt_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); 562void ffrt_task_handle_destroy(ffrt_task_handle_t handle); 563``` 564 565##### 参数 566 567`func` 568 569* CPU Function的指针,该指针执行的数据结构,按照`ffrt_function_header_t`定义的描述了该CPU Task如何执行和销毁的函数指针,FFRT通过这两个函数指针完成Task的执行和销毁。 570 571`in_deps` 572 573* 该参数是可选的。 574* 该参数用于描述该任务的输入依赖,FFRT 通过数据的虚拟地址作为数据的Signature 来建立依赖。 575 576`out_deps` 577 578* 该参数是可选的。 579* 该参数用于描述该任务的输出依赖。 580* `注意`:该依赖值本质上是一个数值,ffrt没办法区分该值是合理还是不合理的,会假定输入的值是合理的进行处理;但不建议采用NULL,1, 2 等值来建立依赖关系,建议采用实际的内存地址,因为前者使用不当会建立起不必要的依赖,影响并发。 581 582`attr` 583 584* 该参数是可选的。 585* 该参数用于描述Task 的属性,比如qos 等,详见 [ffrt_task_attr_t](#ffrt_task_attr_t)章节。 586 587##### 返回值 588 589* task 的句柄,该句柄可以用于建立task 之间的依赖,或用于在wait 语句中实现同步。 590 591##### 描述 592 593* **C API中的ffrt_task_handle_t需要用户调用`ffrt_task_handle_destroy`显式销毁。** 594* C API中的task_handle_t对象的置空和销毁由用户完成,对同一个ffrt_task_handle_t仅能调用一次`ffrt_task_handle_destroy`,重复对同一个ffrt_task_handle_t调用`ffrt_task_handle_destroy`,其行为是未定义的。 595* 在`ffrt_task_handle_destroy`之后再对ffrt_task_handle_t进行访问,其行为是未定义的。 596 597##### 样例 598 599```{.c} 600#include <stdio.h> 601#include "ffrt.h" 602 603void func0(void* arg) 604{ 605 printf("hello "); 606} 607 608void func1(void* arg) 609{ 610 (*(int*)arg)++; 611} 612 613void func2(void* arg) 614{ 615 printf("world, x = %d\n", *(int*)arg); 616} 617 618void func3(void* arg) 619{ 620 printf("handle wait"); 621 (*(int*)arg)++; 622} 623 624typedef struct { 625 ffrt_function_header_t header; 626 ffrt_function_t func; 627 ffrt_function_t after_func; 628 void* arg; 629} c_function; 630 631static void ffrt_exec_function_wrapper(void* t) 632{ 633 c_function* f = (c_function*)t; 634 if (f->func) { 635 f->func(f->arg); 636 } 637} 638 639static void ffrt_destroy_function_wrapper(void* t) 640{ 641 c_function* f = (c_function*)t; 642 if (f->after_func) { 643 f->after_func(f->arg); 644 } 645} 646 647#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1]) 648static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func, 649 const ffrt_function_t after_func, void* arg) 650{ 651 FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size, 652 size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size); 653 c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general); 654 f->header.exec = ffrt_exec_function_wrapper; 655 f->header.destroy = ffrt_destroy_function_wrapper; 656 f->func = func; 657 f->after_func = after_func; 658 f->arg = arg; 659 return (ffrt_function_header_t*)f; 660} 661 662static inline ffrt_task_handle_t ffrt_submit_h_c(ffrt_function_t func, const ffrt_function_t after_func, 663 void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr) 664{ 665 return ffrt_submit_h_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr); 666} 667 668static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func, 669 void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr) 670{ 671 ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr); 672} 673 674 675int main(int narg, char** argv) 676{ 677 // handle work with submit 678 ffrt_task_handle_t h = ffrt_submit_h_c(func0, NULL, NULL, NULL, NULL, NULL); // not need some data in this task 679 int x = 1; 680 const std::vector<ffrt_dependence_t> in_deps = {{ffrt_dependence_data, &x}}; 681 ffrt_deps_t d2{static_cast<uint32_t>(in_deps.size()), in_deps.data()}; 682 683 const std::vector<ffrt_dependence_t> out_deps = {{ffrt_dependence_data, &x}}; 684 ffrt_deps_t d1{static_cast<uint32_t>(out_deps.size()), out_deps.data()}; 685 686 ffrt_submit_c(func1, NULL, &x, NULL, &d1, NULL); 687 ffrt_submit_c(func2, NULL, &x, &d2, NULL, NULL); // this task depend x and h 688 ffrt_task_handle_destroy(h); 689 690 // handle work with wait 691 ffrt_task_handle_t h2 = ffrt_submit_h_c(func3, NULL, &x, NULL, NULL, NULL); 692 693 const std::vector<ffrt_dependence_t> wait_deps = {{ffrt_dependence_task, h2}}; 694 ffrt_deps_t d3{static_cast<uint32_t>(wait_deps.size()), wait_deps.data()}; 695 ffrt_wait_deps(&d3); 696 ffrt_task_handle_destroy(h2); 697 printf("x = %d", x); 698 ffrt_wait(); 699 return 0; 700} 701``` 702 703* 预期的输出为: 704 705``` 706hello 707handle wait 708x = 2 709world, x = 3 710``` 711 712 713 714#### ffrt_this_task_get_id 715 716<hr/> 717 718* 返回当前task的id标识,更多使用用于维测(原因是task name可能重名)。 719 720##### 声明 721 722```{.c} 723uint64_t ffrt_this_task_get_id(); 724``` 725 726##### 参数 727 728* 不涉及。 729 730##### 返回值 731 732* 当前task的id。 733 734##### 描述 735 736* 该接口在task内部调用将返回当前task的id标识,在task外部调用将返回0。 737* 可以基于该接口在task外部调用返回0的特性来区分函数是运行在FFRT 工作线程上还是非FFRT工作线程上。 738* task id为从1开始编码,每提交一个task便增加1,被设计成64bit,即便是每秒百万次提交,也需要292471.2年才会发生翻转。 739 740##### 样例 741 742* 忽略。 743 744#### ffrt_this_task_update_qos 745 746<hr/> 747 748* 更新当前正在执行的task的qos等级。 749 750##### 声明 751 752```{.c} 753int ffrt_this_task_update_qos(ffrt_qos_t qos); 754``` 755 756##### 参数 757 758* `qos` 新的qos等级。 759 760##### 返回值 761 762* 0表示成功,非0表示失败。 763 764##### 描述 765 766* 该接口对当前task的qos调整会立即生效。 767* 如果新设定的qos与当前的qos不一致,则会block当前task的执行,再按照新的qos恢复执行。 768* 如果新设定的qos与当前的qos一致,则接口会立即返回0,不做任何处理。 769* **如果在非task内部调用该接口,则返回非0值,用户可以选择忽略或其他处理。** 770 771##### 样例 772 773* 忽略。 774 775#### ffrt_this_task_get_qos 776 777<hr/> 778 779* 获取当前正在执行的task的qos等级。 780 781##### 声明 782 783```{.c} 784ffrt_qos_t ffrt_this_task_get_qos(); 785``` 786 787##### 参数 788 789* NA 790 791##### 返回值 792 793* `qos` 任务qos等级。 794 795##### 描述 796 797* 获取当前正在执行的task的qos等级。 798 799##### 样例 800 801```{.c} 802#include "ffrt.h" 803 804int main(int narg, char** argv) 805{ 806 static int x = 0; 807 int* xf = &x; 808 void* data = xf; 809 uint64_t timeout1 = 20; 810 811 ffrt::submit([=]() { 812 ffrt_qos_t taskQos = ffrt_this_task_get_qos(); 813 ffrt_timer_cb cb; 814 ffrt_timer_start(taskQos, timeout1, data, cb, false); 815 ffrt_usleep(200); 816 }, {}, {}); 817 ffrt::wait(); 818 return 0; 819} 820 821``` 822 823### 串行队列 824<hr /> 825* 串行队列基于FFRT协程调度模型,实现了消息队列功能。串行任务执行在FFRT Workers上,用户无需维护一个专用的线程,拥有更轻量级的调度开销。 826 827#### ffrt_queue_attr_t 828 829##### 声明 830```{.c} 831typedef struct { 832 uint32_t storage[(ffrt_queue_attr_storage_size + sizeof(uint32_t) - 1) / sizeof(uint32_t)]; 833} ffrt_queue_attr_t; 834 835int ffrt_queue_attr_init(ffrt_queue_attr_t* attr); 836void ffrt_queue_attr_destroy(ffrt_queue_attr_t* attr); 837``` 838 839##### 参数 840 841`attr` 842* 该参数是指向未初始化的ffrt_queue_attr_t。 843 844##### 返回值 845* 若成功返回0,否则返回-1。 846 847##### 描述 848* ffrt_queue_attr_t用于创建ffrt_queue_t且不单独使用,因此必须在创建队列前先创建好队列属性。 849* ffrt_queue_attr_t对象的置空和销毁由用户完成,对同一个ffrt_queue_attr_t仅能调用一次`ffrt_queue_attr_destroy`,重复对同一个ffrt_queue_attr_t调用`ffrt_queue_attr_destroy`,其行为是未定义的。 850* 在`ffrt_queue_attr_destroy`之后再对ffrt_queue_attr_t进行访问,其行为是未定义的。 851 852##### 样例 853参考ffrt_queue_t章节的样例。 854 855#### ffrt_queue_t 856 857##### 声明 858```{.c} 859typedef enum { ffrt_queue_serial, ffrt_queue_concurrent, ffrt_queue_max } ffrt_queue_type_t; 860typedef void* ffrt_queue_t; 861 862ffrt_queue_t ffrt_queue_create(ffrt_queue_type_t type, const char* name, const ffrt_queue_attr_t* attr) 863void ffrt_queue_destroy(ffrt_queue_t queue) 864``` 865 866##### 参数 867 868`type` 869* 该参数用于描述创建的队列类型。 870 871`name` 872* 该参数用于描述创建队列的名字。 873 874`attr` 875* 该参数用于描述queue的属性,详见ffrt_queue_attr_t章节。 876 877##### 返回值 878* 若成功则返回新创建的队列,否则返回空指针。 879 880##### 描述 881* 提交至该队列的任务将按照顺序执行,如果某个提交的任务中发生阻塞,则无法保证该任务的执行顺序。 882* ffrt_queue_t对象的置空和销毁由用户完成,对同一个ffrt_queue_t仅能调用一次`ffrt_queue_destroy`,重复对同一个ffrt_queue_t调用`ffrt_queue_destroy`,其行为是未定义的。 883* 在`ffrt_queue_destroy`之后再对ffrt_queue_t进行访问,其行为是未定义的。 884 885##### 样例 886``` 887#include <stdio.h> 888#include "ffrt.h" 889 890using namespace std; 891 892template<class T> 893struct Function { 894 ffrt_function_header_t header; 895 T closure; 896}; 897 898template<class T> 899void ExecFunctionWrapper(void* t) 900{ 901 auto f = reinterpret_cast<Function<std::decay_t<T>>*>(t); 902 f->closure(); 903} 904 905template<class T> 906void DestroyFunctionWrapper(void* t) 907{ 908 auto f = reinterpret_cast<Function<std::decay_t<T>>*>(t); 909 f = nullptr; 910} 911 912template<class T> 913static inline ffrt_function_header_t* create_function_wrapper(T&& func, 914 ffrt_function_kind_t kind = ffrt_function_kind_general) 915{ 916 using function_type = Function<std::decay_t<T>>; 917 auto p = ffrt_alloc_auto_managed_function_storage_base(kind); 918 auto f = new (p)function_type; 919 f->header.exec = ExecFunctionWrapper<T>; 920 f->header.destroy = DestroyFunctionWrapper<T>; 921 f->closure = std::forward<T>(func); 922 return reinterpret_cast<ffrt_function_header_t*>(f); 923} 924 925int main(int narg, char** argv) 926{ 927 ffrt_queue_attr_t queue_attr; 928 (void)ffrt_queue_attr_init(&queue_attr); 929 ffrt_queue_t queue_handle = ffrt_queue_create(ffrt_queue_serial, "test_queue", &queue_attr); 930 std::function<void()>&& queueFunc = [] () {printf("Task done.\n");}; 931 ffrt_function_header_t* queueFunc_t = create_function_wrapper((queueFunc), ffrt_function_kind_queue); 932 ffrt_queue_submit(queue_handle, queueFunc_t, nullptr); 933 934 ffrt_queue_attr_destroy(&queue_attr); 935 ffrt_queue_destroy(queue_handle); 936} 937``` 938 939#### ffrt_get_main_queue 940<hr/> 941获取主线程任务队列。 942 943##### 声明 944```{.c} 945ffrt_queue_t ffrt_get_main_queue(); 946``` 947 948##### 参数 949 950NA 951 952##### 返回值 953 954主线程队列。 955 956##### 描述 957获取主线程队列,用于FFRT线程与主线程通信。 958 959##### 样例 960```{.c} 961本用例需要在鸿蒙系统中执行 962#include "ffrt.h" 963 964inline void OnePlusForTest(void* data) 965{ 966 *(int*)data += 1; 967} 968 969int main(int narg, char** argv) 970{ 971 ffrt::queue *serialQueue = new ffrt::queue("ffrt_normal_queue", {}); 972 ffrt_queue_t mainQueue = ffrt_get_main_queue(); 973 ffrt_task_attr_t attr; 974 ffrt_task_attr_init(&attr); 975 ffrt_task_attr_set_qos(&attr, ffrt_qos_user_initiated); 976 int result = 0; 977 std::function<void()>&& basicFunc = [&result]() { 978 OnePlusForTest(static_cast<void*>(&result)); 979 OnePlusForTest(static_cast<void*>(&result)); 980 ffrt_usleep(3000); 981 }; 982 983 ffrt::task_handle handle = serialQueue->submit_h( 984 [&] { 985 result = result + 1; 986 ffrt_queue_submit(mainQueue, ffrt::create_function_wrapper(basicFunc, ffrt_function_kind_queue), 987 &attr); 988 }, 989 ffrt::task_attr().qos(3).name("ffrt main_queue.")); 990 991 serialQueue->wait(handle); 992 return 0; 993} 994``` 995 996 997#### ffrt_get_current_queue 998 999获取ArkTS Worker线程任务队列。 1000 1001##### 声明 1002```{.c} 1003ffrt_queue_t ffrt_get_current_queue(); 1004``` 1005 1006##### 参数 1007 1008NA 1009 1010##### 返回值 1011 1012ArkTS Worker线程任务队列。 1013 1014##### 描述 1015获取ArkTS Worker线程队列,用于FFRT线程与ArkTS Worker线程通信。 1016 1017##### 样例 1018```{.c} 1019//本用例需要在鸿蒙系统中执行 1020#include "ffrt.h" 1021 1022inline void OnePlusForTest(void* data) 1023{ 1024 *(int*)data += 1; 1025} 1026 1027int main(int narg, char** argv) 1028{ 1029 ffrt::queue *serialQueue = new ffrt::queue("ffrt_normal_queue", {}); 1030 ffrt_queue_t currentQueue = ffrt_get_current_queue(); 1031 ffrt_task_attr_t attr; 1032 ffrt_task_attr_init(&attr); 1033 ffrt_task_attr_set_qos(&attr, ffrt_qos_user_initiated); 1034 int result = 0; 1035 std::function<void()>&& basicFunc = [&result]() { 1036 OnePlusForTest(static_cast<void*>(&result)); 1037 OnePlusForTest(static_cast<void*>(&result)); 1038 ffrt_usleep(3000); 1039 }; 1040 1041 ffrt::task_handle handle = serialQueue->submit_h( 1042 [&] { 1043 result = result + 1; 1044 ffrt_queue_submit(currentQueue, ffrt::create_function_wrapper(basicFunc, ffrt_function_kind_queue), 1045 &attr); 1046 }, 1047 ffrt::task_attr().qos(3).name("ffrt current_queue.")); 1048 1049 serialQueue->wait(handle); 1050 return 0; 1051} 1052``` 1053 1054 1055### 并行队列 1056<hr /> 1057FFRT支持并行队列,并支持设置并行队列的并发度和任务优先级。 1058 1059#### ffrt_queue_attr_set_max_concurrency 1060<hr/> 1061FFRT并行队列设置最大并发度。 1062 1063##### 声明 1064```{.c} 1065void ffrt_queue_attr_set_max_concurrency(ffrt_queue_attr_t* attr, const int max_concurrency); 1066``` 1067 1068##### 参数 1069 1070`attr` 1071 1072* 该参数用于描述queue的属性,详见ffrt_queue_attr_t章节。 1073 1074`max_concurrency` 1075 1076* 最大并发度,当用户设置小于等于0时,并发度是1。 1077 1078##### 返回值 1079 1080NA 1081 1082##### 描述 1083FFRT并行队列设置最大并发度,需要注意的是,当设置很大的并发度时,如100,受限于硬件能力,最终的并发度不会达到100。 1084 1085##### 样例 1086```{.c} 1087#include "ffrt.h" 1088 1089int main(int narg, char** argv) 1090{ 1091 ffrt_queue_attr_t queue_attr; 1092 (void)ffrt_queue_attr_init(&queue_attr); 1093 uint64_t concurrency = 4; 1094 ffrt_queue_attr_set_max_concurrency(&queue_attr, concurrency); 1095 concurrency = ffrt_queue_attr_get_max_concurrency(&queue_attr); 1096 ffrt_queue_attr_destroy(&queue_attr); 1097 printf("concurrency=%lu\n", concurrency); 1098 return 0; 1099} 1100``` 1101 1102预期输出为: 1103 1104``` 1105concurrency=4 1106``` 1107 1108#### ffrt_queue_attr_get_max_concurrency 1109<hr/> 1110获取FFRT并行队列设置的最大并发度。 1111 1112##### 声明 1113```{.c} 1114int ffrt_queue_attr_get_max_concurrency(const ffrt_queue_attr_t* attr); 1115``` 1116 1117##### 参数 1118 1119`attr` 1120 1121* 该参数用于描述queue的属性,详见ffrt_queue_attr_t章节。 1122 1123##### 返回值 1124 1125用户设置的最大并发度。 1126 1127##### 描述 1128获取FFRT并行队列设置的最大并发度。 1129 1130##### 样例 1131```{.c} 1132#include "ffrt.h" 1133 1134int main(int narg, char** argv) 1135{ 1136 ffrt_queue_attr_t queue_attr; 1137 (void)ffrt_queue_attr_init(&queue_attr); 1138 uint64_t concurrency = 4; 1139 ffrt_queue_attr_set_max_concurrency(&queue_attr, concurrency); 1140 concurrency = ffrt_queue_attr_get_max_concurrency(&queue_attr); 1141 ffrt_queue_attr_destroy(&queue_attr); 1142 printf("concurrency=%lu\n", concurrency); 1143 return 0; 1144} 1145``` 1146 1147预期输出为: 1148 1149``` 1150concurrency=4 1151``` 1152 1153#### ffrt_task_attr_set_queue_priority 1154<hr/> 1155设置并行队列任务优先级。 1156 1157##### 声明 1158```{.c} 1159/* 任务优先级 */ 1160typedef enum { 1161ffrt_queue_priority_immediate = 0, 1162ffrt_queue_priority_high, 1163ffrt_queue_priority_low, 1164ffrt_queue_priority_idle, 1165} ffrt_queue_priority_t; 1166 1167void ffrt_task_attr_set_queue_priority(ffrt_task_attr_t* attr, ffrt_queue_priority_t priority); 1168``` 1169 1170##### 参数 1171 1172`attr` 1173 1174* 该参数用于描述task的属性,详见ffrt_task_attr_t章节。 1175 1176`priority` 1177 1178* 任务优先级,支持四种优先级,定义参考ffrt_queue_priority_t。 1179 1180##### 返回值 1181 1182NA 1183 1184##### 描述 1185设置并行队列任务优先级。 1186 1187##### 样例 1188```{.c} 1189#include "ffrt.h" 1190 1191int main(int narg, char** argv) 1192{ 1193 ffrt_task_attr_t task_attr; 1194 (void)ffrt_task_attr_init(&task_attr); 1195 ffrt_queue_priority_t priority = ffrt_queue_priority_idle; 1196 ffrt_task_attr_set_queue_priority(&task_attr, priority); 1197 priority = ffrt_task_attr_get_queue_priority(&task_attr); 1198 ffrt_task_attr_destroy(&task_attr); 1199 printf("priority=%d\n", priority); 1200 return 0; 1201} 1202``` 1203 1204预期输出为: 1205 1206``` 1207priority=3 1208``` 1209 1210#### ffrt_task_attr_get_queue_priority 1211<hr/> 1212获取开发者设置的并行队列任务优先级。 1213 1214##### 声明 1215```{.c} 1216ffrt_queue_priority_t ffrt_task_attr_get_queue_priority(const ffrt_task_attr_t* attr); 1217``` 1218 1219##### 参数 1220 1221`attr` 1222 1223* 该参数用于描述queue的属性,详见ffrt_queue_attr_t章节。 1224 1225##### 返回值 1226 1227任务优先级。 1228 1229##### 描述 1230获取开发者设置的并行队列任务优先级。 1231 1232##### 样例 1233```{.c} 1234#include "ffrt.h" 1235 1236int main(int narg, char** argv) 1237{ 1238 ffrt_task_attr_t task_attr; 1239 (void)ffrt_task_attr_init(&task_attr); 1240 ffrt_queue_priority_t priority = ffrt_queue_priority_idle; 1241 ffrt_task_attr_set_queue_priority(&task_attr, priority); 1242 priority = ffrt_task_attr_get_queue_priority(&task_attr); 1243 ffrt_task_attr_destroy(&task_attr); 1244 printf("priority=%d\n", priority); 1245 return 0; 1246} 1247``` 1248 1249预期输出为: 1250 1251``` 1252priority=3 1253``` 1254 1255### 同步原语 1256 1257#### ffrt_mutex_t 1258<hr/> 1259* FFRT提供的类似pthread mutex 的性能实现。 1260 1261##### 声明 1262 1263```{.c} 1264typedef enum { 1265 ffrt_error = -1, 1266 ffrt_success = 0, 1267 ffrt_error_nomem = ENOMEM, 1268 ffrt_error_timedout = ETIMEDOUT, 1269 ffrt_error_busy = EBUSY, 1270 ffrt_error_inval = EINVAL 1271} ffrt_error_t; 1272 1273struct ffrt_mutex_t; 1274 1275int ffrt_mutex_init(ffrt_mutex_t* mutex, const ffrt_mutexattr_t* attr); 1276int ffrt_mutex_lock(ffrt_mutex_t* mutex); 1277int ffrt_mutex_unlock(ffrt_mutex_t* mutex); 1278int ffrt_mutex_trylock(ffrt_mutex_t* mutex); 1279int ffrt_mutex_destroy(ffrt_mutex_t* mutex); 1280``` 1281 1282##### 参数 1283 1284`attr` 1285 1286* 当前FFRT只支持基础类型的mutex,因此attr必须为空指针。 1287 1288`mutex` 1289 1290* 指向所操作的互斥锁的指针。 1291 1292##### 返回值 1293 1294* 若成功则为 ffrt_success ,否则发生错误。 1295 1296##### 描述 1297* 该接口只能在FFRT task 内部调用,在FFRT task 外部调用存在未定义的行为。 1298* 该功能能够避免pthread传统的pthread_mutex_t 在抢不到锁时陷入内核的问题,在使用得当的条件下将会有更好的性能。 1299* **注意:目前暂不支持递归和定时功能。** 1300* **注意:C API中的ffrt_mutex_t需要用户调用`ffrt_mutex_init`和`ffrt_mutex_destroy`显式创建和销毁。** 1301* **注意:C API中的ffrt_mutex_t对象的置空和销毁由用户完成,对同一个ffrt_mutex_t仅能调用一次`ffrt_mutex_destroy`,重复对同一个ffrt_mutex_t调用`ffrt_mutex_destroy`,其行为是未定义的。** 1302* **注意:在`ffrt_mutex_destroy`之后再对ffrt_mutex_t进行访问,其行为是未定义的。** 1303 1304##### 样例 1305 1306```{.c} 1307#include <stdio.h> 1308#include "ffrt.h" 1309 1310typedef struct { 1311 int* sum; 1312 ffrt_mutex_t* mtx; 1313} tuple; 1314 1315void func(void* arg) 1316{ 1317 tuple* t = (tuple*)arg; 1318 1319 int ret = ffrt_mutex_lock(t->mtx); 1320 if (ret != ffrt_success) { 1321 printf("error\n"); 1322 } 1323 (*t->sum)++; 1324 ret = ffrt_mutex_unlock(t->mtx); 1325 if (ret != ffrt_success) { 1326 printf("error\n"); 1327 } 1328} 1329 1330typedef struct { 1331 ffrt_function_header_t header; 1332 ffrt_function_t func; 1333 ffrt_function_t after_func; 1334 void* arg; 1335} c_function; 1336 1337static void ffrt_exec_function_wrapper(void* t) 1338{ 1339 c_function* f = (c_function*)t; 1340 if (f->func) { 1341 f->func(f->arg); 1342 } 1343} 1344 1345static void ffrt_destroy_function_wrapper(void* t) 1346{ 1347 c_function* f = (c_function*)t; 1348 if (f->after_func) { 1349 f->after_func(f->arg); 1350 } 1351} 1352 1353#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1]) 1354static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func, 1355 const ffrt_function_t after_func, void* arg) 1356{ 1357 FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size, 1358 size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size); 1359 c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general); 1360 f->header.exec = ffrt_exec_function_wrapper; 1361 f->header.destroy = ffrt_destroy_function_wrapper; 1362 f->func = func; 1363 f->after_func = after_func; 1364 f->arg = arg; 1365 return (ffrt_function_header_t*)f; 1366} 1367 1368static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func, 1369 void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr) 1370{ 1371 ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr); 1372} 1373 1374void ffrt_mutex_task(void *) 1375{ 1376 int sum = 0; 1377 ffrt_mutex_t mtx; 1378 tuple t = {&sum, &mtx}; 1379 int ret = ffrt_mutex_init(&mtx, NULL); 1380 if (ret != ffrt_success) { 1381 printf("error\n"); 1382 } 1383 for (int i = 0; i < 10; i++) { 1384 ffrt_submit_c(func, NULL, &t, NULL, NULL, NULL); 1385 } 1386 ffrt_mutex_destroy(&mtx); 1387 ffrt_wait(); 1388 printf("sum = %d\n", sum); 1389} 1390 1391int main(int narg, char** argv) 1392{ 1393 int r; 1394 ffrt_submit_c(ffrt_mutex_task, NULL, NULL, NULL, NULL, NULL); 1395 ffrt_wait(); 1396 return 0; 1397} 1398``` 1399 1400预期输出为: 1401 1402``` 1403sum=10 1404``` 1405 1406* 该例子为功能示例,实际中并不鼓励这样使用。 1407 1408 1409#### ffrt_cond_t 1410<hr/> 1411 1412* FFRT提供的类似pthread 信号量的性能实现。 1413 1414##### 声明 1415 1416```{.c} 1417typedef enum { 1418 ffrt_error = -1, 1419 ffrt_success = 0, 1420 ffrt_error_nomem = ENOMEM, 1421 ffrt_error_timedout = ETIMEDOUT, 1422 ffrt_error_busy = EBUSY, 1423 ffrt_error_inval = EINVAL 1424} ffrt_error_t; 1425 1426struct ffrt_cond_t; 1427 1428int ffrt_cond_init(ffrt_cond_t* cond, const ffrt_condattr_t* attr); 1429int ffrt_cond_signal(ffrt_cond_t* cond); 1430int ffrt_cond_broadcast(ffrt_cond_t* cond); 1431int ffrt_cond_wait(ffrt_cond_t*cond, ffrt_mutex_t* mutex); 1432int ffrt_cond_timedwait(ffrt_cond_t* cond, ffrt_mutex_t* mutex, const struct timespec* time_point); 1433int ffrt_cond_destroy(ffrt_cond_t* cond); 1434``` 1435 1436##### 参数 1437 1438`cond` 1439 1440* 指向所操作的信号量的指针。 1441 1442`attr` 1443 1444* 属性设定,空指针表示使用默认属性。 1445 1446`mutex` 1447 1448* 指向要在阻塞期间解锁的互斥锁的指针。 1449 1450`time_point` 1451 1452* 指向指定等待时限时间的对象的指针。 1453 1454 1455##### 返回值 1456 1457* 若成功则为 ffrt_success,若在锁定互斥前抵达时限则为 ffrt_error_timedout。 1458 1459##### 描述 1460* 该接口只能在FFRT task 内部调用,在FFRT task 外部调用存在未定义的行为。 1461* 该功能能够避免传统的pthread_cond_t在条件不满足时陷入内核的问题,在使用得当的条件下将会有更好的性能。 1462* **注意:C API中的ffrt_cond_t需要用户调用`ffrt_cond_init`和`ffrt_cond_destroy`显式创建和销毁。** 1463* **注意:C API中的ffrt_cond_t对象的置空和销毁由用户完成,对同一个ffrt_cond_t仅能调用一次`ffrt_cond_destroy`,重复对同一个ffrt_cond_t调用`ffrt_cond_destroy`,其行为是未定义的。** 1464* **注意:在`ffrt_cond_destroy`之后再对ffrt_cond_t进行访问,其行为是未定义的。** 1465 1466##### 样例 1467 1468```{.c} 1469#include <stdio.h> 1470#include "ffrt.h" 1471 1472typedef struct { 1473 ffrt_cond_t* cond; 1474 int* a; 1475 ffrt_mutex_t* lock_; 1476} tuple; 1477 1478void func1(void* arg) 1479{ 1480 tuple* t = (tuple*)arg; 1481 int ret = ffrt_mutex_lock(t->lock_); 1482 if (ret != ffrt_success) { 1483 printf("error\n"); 1484 } 1485 while (*t->a != 1) { 1486 ret = ffrt_cond_wait(t->cond, t->lock_); 1487 if (ret != ffrt_success) { 1488 printf("error\n"); 1489 } 1490 } 1491 ret = ffrt_mutex_unlock(t->lock_); 1492 if (ret != ffrt_success) { 1493 printf("error\n"); 1494 } 1495 printf("a = %d\n", *(t->a)); 1496} 1497 1498void func2(void* arg) 1499{ 1500 tuple* t = (tuple*)arg; 1501 int ret = ffrt_mutex_lock(t->lock_); 1502 if (ret != ffrt_success) { 1503 printf("error\n"); 1504 } 1505 *(t->a) = 1; 1506 ret = ffrt_cond_signal(t->cond); 1507 if (ret != ffrt_success) { 1508 printf("error\n"); 1509 } 1510 ret = ffrt_mutex_unlock(t->lock_); 1511 if (ret != ffrt_success) { 1512 printf("error\n"); 1513 } 1514} 1515 1516typedef struct { 1517 ffrt_function_header_t header; 1518 ffrt_function_t func; 1519 ffrt_function_t after_func; 1520 void* arg; 1521} c_function; 1522 1523static void ffrt_exec_function_wrapper(void* t) 1524{ 1525 c_function* f = (c_function*)t; 1526 if (f->func) { 1527 f->func(f->arg); 1528 } 1529} 1530 1531static void ffrt_destroy_function_wrapper(void* t) 1532{ 1533 c_function* f = (c_function*)t; 1534 if (f->after_func) { 1535 f->after_func(f->arg); 1536 } 1537} 1538 1539#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1]) 1540static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func, 1541 const ffrt_function_t after_func, void* arg) 1542{ 1543 FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size, 1544 size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size); 1545 c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general); 1546 f->header.exec = ffrt_exec_function_wrapper; 1547 f->header.destroy = ffrt_destroy_function_wrapper; 1548 f->func = func; 1549 f->after_func = after_func; 1550 f->arg = arg; 1551 return (ffrt_function_header_t*)f; 1552} 1553 1554static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func, 1555 void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr) 1556{ 1557 ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr); 1558} 1559 1560void ffrt_cv_task(void *) 1561{ 1562 ffrt_cond_t cond; 1563 int ret = ffrt_cond_init(&cond, NULL); 1564 if (ret != ffrt_success) { 1565 printf("error\n"); 1566 } 1567 int a = 0; 1568 ffrt_mutex_t lock_; 1569 tuple t = {&cond, &a, &lock_}; 1570 ret = ffrt_mutex_init(&lock_, NULL); 1571 if (ret != ffrt_success) { 1572 printf("error\n"); 1573 } 1574 ffrt_submit_c(func1, NULL, &t, NULL, NULL, NULL); 1575 ffrt_submit_c(func2, NULL, &t, NULL, NULL, NULL); 1576 ffrt_wait(); 1577 ffrt_cond_destroy(&cond); 1578 ffrt_mutex_destroy(&lock_); 1579} 1580 1581int main(int narg, char** argv) 1582{ 1583 ffrt_submit_c(ffrt_cv_task, NULL, NULL, NULL, NULL, NULL); 1584 ffrt_wait(); 1585 return 0; 1586} 1587``` 1588 1589预期输出为: 1590 1591``` 1592a=1 1593``` 1594 1595* 该例子为功能示例,实际中并不鼓励这样使用。 1596 1597#### ffrt_usleep 1598 1599<hr/> 1600* FFRT提供的类似C11 sleep和linux usleep的性能实现。 1601 1602##### 声明 1603 1604```{.c} 1605int ffrt_usleep(uint64_t usec); 1606``` 1607 1608##### 参数 1609 1610`usec` 1611 1612* 睡眠的us数。 1613 1614##### 返回值 1615 1616* 不涉及。 1617 1618##### 描述 1619* 该接口只能在FFRT task 内部调用,在FFRT task 外部调用存在未定义的行为。 1620* 该功能能够避免传统的sleep 睡眠时陷入内核的问题,在使用得当的条件下将会有更好的性能。 1621 1622##### 样例 1623 1624```{.c} 1625#include <time.h> 1626#include <stdio.h> 1627#include "ffrt.h" 1628 1629void func(void* arg) 1630{ 1631 time_t current_time = time(NULL); 1632 printf("Time: %s", ctime(¤t_time)); 1633 ffrt_usleep(2000000); // 睡眠 2 秒 1634 current_time = time(NULL); 1635 printf("Time: %s", ctime(¤t_time)); 1636} 1637 1638typedef struct { 1639 ffrt_function_header_t header; 1640 ffrt_function_t func; 1641 ffrt_function_t after_func; 1642 void* arg; 1643} c_function; 1644 1645static void ffrt_exec_function_wrapper(void* t) 1646{ 1647 c_function* f = (c_function*)t; 1648 if (f->func) { 1649 f->func(f->arg); 1650 } 1651} 1652 1653static void ffrt_destroy_function_wrapper(void* t) 1654{ 1655 c_function* f = (c_function*)t; 1656 if (f->after_func) { 1657 f->after_func(f->arg); 1658 } 1659} 1660 1661#define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1]) 1662static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func, 1663 const ffrt_function_t after_func, void* arg) 1664{ 1665 FFRT_STATIC_ASSERT(sizeof(c_function) <= ffrt_auto_managed_function_storage_size, 1666 size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size); 1667 c_function* f = (c_function*)ffrt_alloc_auto_managed_function_storage_base(ffrt_function_kind_general); 1668 f->header.exec = ffrt_exec_function_wrapper; 1669 f->header.destroy = ffrt_destroy_function_wrapper; 1670 f->func = func; 1671 f->after_func = after_func; 1672 f->arg = arg; 1673 return (ffrt_function_header_t*)f; 1674} 1675 1676static inline void ffrt_submit_c(ffrt_function_t func, const ffrt_function_t after_func, 1677 void* arg, const ffrt_deps_t* in_deps, const ffrt_deps_t* out_deps, const ffrt_task_attr_t* attr) 1678{ 1679 ffrt_submit_base(ffrt_create_function_wrapper(func, after_func, arg), in_deps, out_deps, attr); 1680} 1681 1682int main(int narg, char** argv) 1683{ 1684 ffrt_submit_c(func, NULL, NULL, NULL, NULL, NULL); 1685 ffrt_wait(); 1686 return 0; 1687} 1688``` 1689 1690一种输出情况为: 1691 1692``` 1693Time: Tue Aug 13 15:45:30 2024 1694Time: Tue Aug 13 15:45:32 2024 1695``` 1696 1697#### ffrt_yield 1698<hr/> 1699* 当前task 主动让出CPU 执行资源,让其他可以被执行的task 先执行,如果没有其他可被执行的task,yield 无效。 1700 1701##### 声明 1702 1703```{.c} 1704void ffrt_yield(); 1705``` 1706 1707##### 参数 1708 1709* 不涉及。 1710 1711##### 返回值 1712 1713* 不涉及。 1714 1715##### 描述 1716* 该接口只能在FFRT task 内部调用,在FFRT task 外部调用存在未定义的行为。 1717* 此函数的确切行为取决于实现,特别是使用中的FFRT 调度程序的机制和系统状态。 1718 1719##### 样例 1720 1721* 省略。 1722 1723### ffrt timer 1724<hr /> 1725FFRT支持启动和停止定时器的能力。 1726 1727#### ffrt_timer_start 1728<hr/> 1729启动timer定时器。 1730 1731##### 声明 1732```{.c} 1733typedef int ffrt_timer_t; 1734typedef void (*ffrt_timer_cb)(void* data); 1735 1736ffrt_timer_t ffrt_timer_start(ffrt_qos_t qos, uint64_t timeout, void* data, ffrt_timer_cb cb, bool repeat); 1737``` 1738 1739##### 参数 1740 1741`qos` 1742 1743* qos等级。 1744 1745`timeout` 1746 1747* 超时时间。 1748 1749`data` 1750 1751* 超时后回调函数的入参。 1752 1753`cb` 1754 1755* 超时后回调函数。 1756 1757`repeat` 1758 1759* 是否重复执行该定时器。 1760 1761##### 返回值 1762 1763返回该定时器句柄。 1764 1765##### 描述 1766启动timer定时器。 1767 1768##### 样例 1769```{.c} 1770#include <stdint.h> 1771#include <unistd.h> 1772#include "ffrt.h" 1773 1774static void testfun(void *data) 1775{ 1776 *(int *)data += 1; 1777} 1778 1779void (*cb)(void *) = testfun; 1780 1781int main(int narg, char** argv) 1782{ 1783 static int x = 0; 1784 int *xf = &x; 1785 void *data = xf; 1786 uint64_t timeout = 200; 1787 int handle = ffrt_timer_start(ffrt_qos_default, timeout, data, cb, false); 1788 usleep(300000); 1789 ffrt_timer_stop(ffrt_qos_default, handle); 1790 printf("data: %d\n", x); 1791 return 0; 1792} 1793``` 1794 1795预期输出为: 1796 1797``` 1798data: 1 1799``` 1800 1801#### ffrt_timer_stop 1802<hr/> 1803停止timer定时器。 1804 1805##### 声明 1806```{.c} 1807int ffrt_timer_stop(ffrt_qos_t qos, ffrt_timer_t handle); 1808``` 1809 1810##### 参数 1811 1812`qos` 1813 1814* qos等级。 1815 1816`handle` 1817 1818* 定时器句柄。 1819 1820##### 返回值 1821 1822返回0成功,返回-1失败。 1823 1824##### 描述 1825停止timer定时器。 1826 1827##### 样例 1828```{.c} 1829#include <stdint.h> 1830#include <unistd.h> 1831#include "ffrt.h" 1832 1833static void testfun(void *data) 1834{ 1835 *(int *)data += 1; 1836} 1837 1838void (*cb)(void *) = testfun; 1839 1840int main(int narg, char** argv) 1841{ 1842 static int x = 0; 1843 int *xf = &x; 1844 void *data = xf; 1845 uint64_t timeout = 200; 1846 int handle = ffrt_timer_start(ffrt_qos_default, timeout, data, cb, false); 1847 usleep(300000); 1848 ffrt_timer_stop(ffrt_qos_default, handle); 1849 printf("data: %d\n", x); 1850 return 0; 1851} 1852``` 1853 1854预期输出为: 1855 1856``` 1857data: 1 1858``` 1859 1860### ffrt looper 1861<hr /> 1862FFRT 提供looper机制,looper支持任务提交,事件监听,定时器功能,looper运行在用户线程。 1863 1864#### ffrt_loop_create 1865<hr/> 1866创建loop对象。 1867 1868##### 声明 1869```{.c} 1870typedef void* ffrt_loop_t; 1871 1872ffrt_loop_t ffrt_loop_create(ffrt_queue_t queue); 1873``` 1874 1875##### 参数 1876 1877`queue` 1878 1879* 需要是并行队列。 1880 1881##### 返回值 1882 1883loop对象。 1884 1885##### 描述 1886创建loop对象。 1887 1888##### 样例 1889```{.c} 1890#include <stdint.h> 1891#include <unistd.h> 1892#include <stdio.h> 1893#include "c/loop.h" 1894 1895int main(int narg, char** argv) 1896{ 1897 ffrt_queue_attr_t queue_attr; 1898 (void)ffrt_queue_attr_init(&queue_attr); 1899 ffrt_queue_t queue_handle = ffrt_queue_create(ffrt_queue_concurrent, "test_queue", &queue_attr); 1900 1901 auto loop = ffrt_loop_create(queue_handle); 1902 1903 if (loop != NULL) { 1904 printf("loop is not null.\n"); 1905 } 1906 1907 int ret = ffrt_loop_destroy(loop); 1908 1909 ffrt_queue_attr_destroy(&queue_attr); 1910 ffrt_queue_destroy(queue_handle); 1911 return 0; 1912} 1913``` 1914 1915预期输出为: 1916 1917``` 1918loop is not null. 1919``` 1920 1921#### ffrt_loop_destroy 1922<hr/> 1923销毁loop对象。 1924 1925##### 声明 1926```{.c} 1927int ffrt_loop_destroy(ffrt_loop_t loop); 1928``` 1929 1930##### 参数 1931 1932`loop` 1933 1934* loop对象。 1935 1936##### 返回值 1937 1938返回0表示成功,-1表示失败。 1939 1940##### 描述 1941销毁loop对象。 1942 1943##### 样例 1944```{.c} 1945#include <stdint.h> 1946#include <unistd.h> 1947#include <stdio.h> 1948#include "c/loop.h" 1949 1950int main(int narg, char** argv) 1951{ 1952 ffrt_queue_attr_t queue_attr; 1953 (void)ffrt_queue_attr_init(&queue_attr); 1954 ffrt_queue_t queue_handle = ffrt_queue_create(ffrt_queue_concurrent, "test_queue", &queue_attr); 1955 1956 auto loop = ffrt_loop_create(queue_handle); 1957 1958 int ret = ffrt_loop_destroy(loop); 1959 1960 if (ret == 0) { 1961 printf("loop normal destruction."); 1962 } 1963 1964 ffrt_queue_attr_destroy(&queue_attr); 1965 ffrt_queue_destroy(queue_handle); 1966 return 0; 1967} 1968``` 1969 1970预期输出为: 1971 1972``` 1973loop normal destruction. 1974``` 1975 1976#### ffrt_loop_run 1977<hr/> 1978启动loop循环。 1979 1980##### 声明 1981```{.c} 1982int ffrt_loop_run(ffrt_loop_t loop); 1983``` 1984 1985##### 参数 1986 1987`loop` 1988 1989* loop对象。 1990 1991##### 返回值 1992 1993返回0表示成功,-1表示失败。 1994 1995##### 描述 1996启动loop循环。 1997 1998##### 样例 1999```{.c} 2000#include <pthread.h> 2001#include <unistd.h> 2002#include <stdio.h> 2003#include "c/loop.h" 2004 2005void* ThreadFunc(void* p) 2006{ 2007 int ret = ffrt_loop_run(p); 2008 if (ret == 0) { 2009 printf("loop normal operation."); 2010 } 2011 return nullptr; 2012} 2013int main(int narg, char** argv) 2014{ 2015 ffrt_queue_attr_t queue_attr; 2016 (void)ffrt_queue_attr_init(&queue_attr); 2017 ffrt_queue_t queue_handle = ffrt_queue_create(ffrt_queue_concurrent, "test_queue", &queue_attr); 2018 2019 auto loop = ffrt_loop_create(queue_handle); 2020 pthread_t thread; 2021 pthread_create(&thread, 0, ThreadFunc, loop); 2022 2023 ffrt_loop_stop(loop); 2024 int ret = ffrt_loop_destroy(loop); 2025 2026 ffrt_queue_attr_destroy(&queue_attr); 2027 ffrt_queue_destroy(queue_handle); 2028 return 0; 2029} 2030``` 2031 2032预期输出为: 2033 2034``` 2035loop normal operation. 2036``` 2037 2038#### ffrt_loop_stop 2039<hr/> 2040停止loop循环。 2041 2042##### 声明 2043```{.c} 2044void ffrt_loop_stop(ffrt_loop_t loop); 2045``` 2046 2047##### 参数 2048 2049`loop` 2050 2051* loop对象。 2052 2053##### 返回值 2054 2055NA。 2056 2057##### 描述 2058停止loop循环。 2059 2060##### 样例 2061```{.c} 2062#include <pthread.h> 2063#include <unistd.h> 2064#include <stdio.h> 2065#include "c/loop.h" 2066 2067void* ThreadFunc(void* p) 2068{ 2069 int ret = ffrt_loop_run(p); 2070 return nullptr; 2071} 2072int main(int narg, char** argv) 2073{ 2074 ffrt_queue_attr_t queue_attr; 2075 (void)ffrt_queue_attr_init(&queue_attr); 2076 ffrt_queue_t queue_handle = ffrt_queue_create(ffrt_queue_concurrent, "test_queue", &queue_attr); 2077 2078 auto loop = ffrt_loop_create(queue_handle); 2079 pthread_t thread; 2080 pthread_create(&thread, 0, ThreadFunc, loop); 2081 2082 ffrt_loop_stop(loop); 2083 int ret = ffrt_loop_destroy(loop); 2084 2085 ffrt_queue_attr_destroy(&queue_attr); 2086 ffrt_queue_destroy(queue_handle); 2087 return 0; 2088} 2089``` 2090 2091预期输出为: 2092 2093``` 2094正常停止loop对象,返回值是0。 2095``` 2096 2097#### ffrt_loop_epoll_ctl 2098<hr/> 2099管理loop上的监听事件。 2100 2101##### 声明 2102```{.c} 2103int ffrt_loop_epoll_ctl(ffrt_loop_t loop, int op, int fd, uint32_t events, void *data, ffrt_poller_cb cb); 2104``` 2105 2106##### 参数 2107 2108`loop` 2109 2110* loop对象。 2111 2112`op` 2113 2114* fd操作符,如EPOLL_CTL_ADD和EPOLL_CLT_DEL。 2115 2116`fd` 2117 2118* 事件描述符。 2119 2120`events` 2121 2122* 事件。 2123 2124`data` 2125 2126* 事件变化时触发的回调函数的入参。 2127 2128`cb` 2129 2130* 事件变化时触发的回调函数。 2131 2132##### 返回值 2133 2134返回0表示成功,-1表示失败。 2135 2136##### 描述 2137管理loop上的监听事件。 2138 2139##### 样例 2140```{.c} 2141#include <pthread.h> 2142#include <unistd.h> 2143#include <stdio.h> 2144#include <functional> 2145#include <sys/epoll.h> 2146#include <sys/eventfd.h> 2147#include "c/loop.h" 2148#include "ffrt.h" 2149 2150void* ThreadFunc(void* p) 2151{ 2152 int ret = ffrt_loop_run(p); 2153 return nullptr; 2154} 2155 2156static void testfun(void* data) 2157{ 2158 *(int*)data += 1; 2159} 2160 2161static void (*cb)(void*) = testfun; 2162 2163void testCallBack(void *data, unsigned int events) {} 2164 2165struct TestData { 2166 int fd; 2167 uint64_t expected; 2168}; 2169 2170int main(int narg, char** argv) 2171{ 2172 ffrt_queue_attr_t queue_attr; 2173 (void)ffrt_queue_attr_init(&queue_attr); 2174 ffrt_queue_t queue_handle = ffrt_queue_create(ffrt_queue_concurrent, "test_queue", &queue_attr); 2175 2176 auto loop = ffrt_loop_create(queue_handle); 2177 int result1 = 0; 2178 std::function<void()> &&basicFunc1 = [&result1]() {result1 += 10;}; 2179 ffrt_task_handle_t task1 = ffrt_queue_submit_h(queue_handle, ffrt::create_function_wrapper(basicFunc1, ffrt_function_kind_queue), nullptr); 2180 2181 pthread_t thread; 2182 pthread_create(&thread, 0, ThreadFunc, loop); 2183 2184 static int x = 0; 2185 int* xf = &x; 2186 void* data = xf; 2187 uint64_t timeout1 = 20; 2188 uint64_t timeout2 = 10; 2189 uint64_t expected = 0xabacadae; 2190 2191 int testFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 2192 struct TestData testData {.fd = testFd, .expected = expected}; 2193 ffrt_timer_t timeHandle = ffrt_loop_timer_start(loop, timeout1, data, cb, false); 2194 2195 int ret = ffrt_loop_epoll_ctl(loop, EPOLL_CTL_ADD, testFd, EPOLLIN, (void*)(&testData), testCallBack); 2196 if (ret == 0) { 2197 printf("ffrt_loop_epoll_ctl执行成功。\n"); 2198 } 2199 ssize_t n = write(testFd, &expected, sizeof(uint64_t)); 2200 usleep(25000); 2201 ffrt_loop_epoll_ctl(loop, EPOLL_CTL_DEL, testFd, 0, nullptr, nullptr); 2202 2203 ffrt_loop_stop(loop); 2204 pthread_join(thread, nullptr); 2205 ffrt_loop_timer_stop(loop, timeHandle); 2206 ret = ffrt_loop_destroy(loop); 2207 2208 ffrt_queue_attr_destroy(&queue_attr); 2209 ffrt_queue_destroy(queue_handle); 2210 return 0; 2211} 2212``` 2213 2214预期输出为: 2215 2216``` 2217ffrt_loop_epoll_ctl执行成功。 2218``` 2219 2220#### ffrt_loop_timer_start 2221<hr/> 2222在loop上启动定时器。 2223 2224##### 声明 2225```{.c} 2226ffrt_timer_t ffrt_loop_timer_start(ffrt_loop_t loop, uint64_t timeout, void* data, ffrt_timer_cb cb, bool repeat); 2227``` 2228 2229##### 参数 2230 2231`loop` 2232 2233* loop对象。 2234 2235`timeout` 2236 2237* 超时时间。 2238 2239`data` 2240 2241* 事件变化时触发的回调函数的入参。 2242 2243`cb` 2244 2245* 事件变化时触发的回调函数。 2246 2247`repeat` 2248 2249* 是否重复执行该定时器。 2250 2251##### 返回值 2252 2253定时器句柄。 2254 2255##### 描述 2256在loop上启动定时器。 2257 2258##### 样例 2259参考ffrt_loop_epoll_ctl接口样例。 2260 2261#### ffrt_loop_timer_stop 2262<hr/> 2263停止timer定时器。 2264 2265##### 声明 2266```{.c} 2267int ffrt_loop_timer_stop(ffrt_loop_t loop, ffrt_timer_t handle) 2268``` 2269 2270##### 参数 2271 2272`loop` 2273 2274* loop对象。 2275 2276`handle` 2277 2278* 定时器句柄。 2279 2280##### 返回值 2281 2282返回0表示成功,返回-1表示失败。 2283 2284##### 描述 2285停止timer定时器。 2286 2287##### 样例 2288参考ffrt_loop_epoll_ctl接口样例。 2289 2290## 长耗时任务监测 2291 2292### 机制 2293* 当任务执行时间超过一秒时,会触发一次堆栈打印,后续该任务堆栈打印频率调整为一分钟。连续打印十次后,打印频率调整为十分钟。再触发十次打印后,打印频率固定为三十分钟。 2294* 该机制的堆栈打印调用的是DFX的 `GetBacktraceStringByTid` 接口,该接口会向阻塞线程发送抓栈信号,触发中断并抓取调用栈返回。 2295 2296### 样例 2297在对应进程日志中搜索 `RecordSymbolAndBacktrace` 关键字,对应的日志示例如下: 2298 2299``` 2300W C01719/ffrt: 60500:RecordSymbolAndBacktrace:159 Tid[16579] function occupies worker for more than [1]s. 2301W C01719/ffrt: 60501:RecordSymbolAndBacktrace:164 Backtrace: 2302W C01719/ffrt: #00 pc 00000000000075f0 /system/lib64/module/file/libhash.z.so 2303W C01719/ffrt: #01 pc 0000000000008758 /system/lib64/module/file/libhash.z.so 2304W C01719/ffrt: #02 pc 0000000000012b98 /system/lib64/module/file/libhash.z.so 2305W C01719/ffrt: #03 pc 000000000002aaa0 /system/lib64/platformsdk/libfilemgmt_libn.z.so 2306W C01719/ffrt: #04 pc 0000000000054b2c /system/lib64/platformsdk/libace_napi.z.so 2307W C01719/ffrt: #05 pc 00000000000133a8 /system/lib64/platformsdk/libuv.so 2308W C01719/ffrt: #06 pc 00000000000461a0 /system/lib64/chipset-sdk/libffrt.so 2309W C01719/ffrt: #07 pc 0000000000046d44 /system/lib64/chipset-sdk/libffrt.so 2310W C01719/ffrt: #08 pc 0000000000046a6c /system/lib64/chipset-sdk/libffrt.so 2311W C01719/ffrt: #09 pc 00000000000467b0 /system/lib64/chipset-sdk/libffrt.so 2312``` 2313该维测会打印出worker上执行时间超过阈值的任务堆栈、worker线程号、执行时间,请自行根据堆栈找对应组件确认阻塞原因。 2314 2315 2316### 注意事项 2317长耗时任务监测会发送中断信号,如果用户的代码中存在 `sleep` 等会被中断唤醒的阻塞,用户需主动接收该阻塞的返回值,并重新调用。 2318示例如下: 2319``` 2320unsigned int leftTime = sleep(10); 2321while (leftTime != 0) { 2322 leftTime = sleep(leftTime); 2323} 2324``` 2325 2326## 开发步骤 2327 2328以下步骤描述了如何使用`FFRT`提供的Native API接口,创建并行任务和串行队列任务以及销毁相应资源。 2329 2330**添加动态链接库** 2331 2332CMakeLists.txt中添加以下lib: 2333```txt 2334libffrt.z.so 2335``` 2336 2337**头文件** 2338```c++ 2339#include "ffrt/task.h" 2340#include "ffrt/type_def.h" 2341#include "ffrt/condition_variable.h" 2342#include "ffrt/mutex.h" 2343#include "ffrt/queue.h" 2344#include "ffrt/sleep.h" 2345``` 2346 23471. **首先需要对执行的函数进行封装**。 2348 ```c++ 2349 // 第一种使用模板,支持C++ 2350 template<class T> 2351 struct Function { 2352 ffrt_function_header_t header; 2353 T closure; 2354 }; 2355 2356 template<class T> 2357 void ExecFunctionWrapper(void* t) 2358 { 2359 auto f = reinterpret_cast<Function<std::decay_t<T>>*>(t); 2360 f->closure(); 2361 } 2362 2363 template<class T> 2364 void DestroyFunctionWrapper(void* t) 2365 { 2366 auto f = reinterpret_cast<Function<std::decay_t<T>>*>(t); 2367 f->closure = nullptr; 2368 } 2369 2370 template<class T> 2371 static inline ffrt_function_header_t* create_function_wrapper(T&& func, 2372 ffrt_function_kind_t kind = ffrt_function_kind_general) 2373 { 2374 using function_type = Function<std::decay_t<T>>; 2375 auto p = ffrt_alloc_auto_managed_function_storage_base(kind); 2376 auto f = new (p)function_type; 2377 f->header.exec = ExecFunctionWrapper<T>; 2378 f->header.destroy = DestroyFunctionWrapper<T>; 2379 f->closure = std::forward<T>(func); 2380 return reinterpret_cast<ffrt_function_header_t*>(f); 2381 } 2382 2383 // 第二种创建方式 2384 typedef struct { 2385 ffrt_function_header_t header; 2386 ffrt_function_t func; 2387 ffrt_function_t after_func; 2388 void* arg; 2389 } CFunction; 2390 2391 static void FfrtExecFunctionWrapper(void* t) 2392 { 2393 CFunction* f = static_cast<CFunction*>(t); 2394 if (f->func) { 2395 f->func(f->arg); 2396 } 2397 } 2398 2399 static void FfrtDestroyFunctionWrapper(void* t) 2400 { 2401 CFunction* f = static_cast<CFunction*>(t); 2402 if (f->after_func) { 2403 f->after_func(f->arg); 2404 } 2405 } 2406 2407 #define FFRT_STATIC_ASSERT(cond, msg) int x(int static_assertion_##msg[(cond) ? 1 : -1]) 2408 static inline ffrt_function_header_t* ffrt_create_function_wrapper(const ffrt_function_t func, 2409 const ffrt_function_t after_func, void* arg, ffrt_function_kind_t kind_t = ffrt_function_kind_general) 2410 { 2411 FFRT_STATIC_ASSERT(sizeof(CFunction) <= ffrt_auto_managed_function_storage_size, 2412 size_of_function_must_be_less_than_ffrt_auto_managed_function_storage_size); 2413 CFunction* f = static_cast<CFunction*>(ffrt_alloc_auto_managed_function_storage_base(kind_t)); 2414 f->header.exec = FfrtExecFunctionWrapper; 2415 f->header.destroy = FfrtDestroyFunctionWrapper; 2416 f->func = func; 2417 f->after_func = after_func; 2418 f->arg = arg; 2419 return reinterpret_cast<ffrt_function_header_t*>(f); 2420 } 2421 2422 // 样例:待提交执行的函数 2423 void OnePlusForTest(void* arg) 2424 { 2425 (*static_cast<int*>(arg)) += 1; 2426 } 2427 ``` 2428 24292. **设置task属性值**。 2430 2431 用户提交任务时可以设置任务属性,包括qos等级,名称等,具体可参考接口文档。 2432 ```c++ 2433 // ******初始化并行任务属性****** 2434 ffrt_task_attr_t attr; 2435 ffrt_task_attr_init(&attr); 2436 2437 // ******创建串行队列****** 2438 2439 // 创建串行队列的属性 2440 ffrt_queue_attr_t queue_attr; 2441 // 创建串行队列的handle 2442 ffrt_queue_t queue_handle; 2443 2444 // 初始化队列属性 2445 (void)ffrt_queue_attr_init(&queue_attr); 2446 2447 // 如有需要,设置指定qos等级 2448 ffrt_queue_attr_set_qos(&queue_attr, static_cast<ffrt_qos_t>(ffrt_qos_inherit)); 2449 // 如有需要,设置超时时间(ms) 2450 ffrt_queue_attr_set_timeout(&queue_attr, 10000); 2451 // 如有需要,设置超时回调 2452 int x = 0; 2453 ffrt_queue_attr_set_callback(&queue_attr, ffrt_create_function_wrapper(OnePlusForTest, NULL, &x, 2454 ffrt_function_kind_queue)); 2455 2456 // 基于属性,初始化队列 2457 queue_handle = ffrt_queue_create(ffrt_queue_serial, "test_queue", &queue_attr); 2458 ``` 2459 24603. **提交任务**。 2461 ```c++ 2462 int a = 0; 2463 // ******并行任务****** 2464 // 提交不带handle返回值的并行任务 2465 ffrt_submit_base(ffrt_create_function_wrapper(OnePlusForTest, NULL, &a), NULL, NULL, &attr); 2466 // 提交带handle返回值的并行任务 2467 ffrt_task_handle_t task = ffrt_submit_h_base( 2468 ffrt_create_function_wrapper(OnePlusForTest, NULL, &a), NULL, NULL, &attr); 2469 2470 // ******串行任务****** 2471 // 提交不返回handle的串行队列任务 2472 ffrt_queue_submit(queue_handle, ffrt_create_function_wrapper(OnePlusForTest, nullptr, &a, 2473 ffrt_function_kind_queue), nullptr); 2474 // 提交带handle的串行队列任务 2475 ffrt_task_handle_t handle = ffrt_queue_submit_h(queue_handle, 2476 ffrt_create_function_wrapper(OnePlusForTest, nullptr, &a, ffrt_function_kind_queue), nullptr); 2477 2478 // 如果需要等待执行结果,则调用wait 2479 const std::vector<ffrt_dependence_t> wait_deps = {{ffrt_dependence_task, task}}; 2480 ffrt_deps_t wait{static_cast<uint32_t>(wait_deps.size()), wait_deps.data()}; 2481 ffrt_wait_deps(&wait); 2482 2483 ffrt_queue_wait(handle); 2484 ``` 2485 24864. **任务提交完成后销毁相应资源**。 2487 ```c++ 2488 // ******销毁并行任务****** 2489 ffrt_task_attr_destroy(&attr); 2490 ffrt_task_handle_destroy(task); 2491 2492 // ******销毁串行队列任务****** 2493 // 先销毁任务handle,再销毁队列 2494 ffrt_queue_attr_destroy(&queue_attr); 2495 ffrt_task_handle_destroy(handle); 2496 ffrt_queue_destroy(queue_handle); 2497 ``` 2498 2499## 使用建议 2500 2501### 建议1: 函数化 2502 2503**基本思想:计算过程函数化** 2504 2505* 程序过程各步骤以函数封装表达,函数满足类纯函数特性。 2506* 无全局数据访问。 2507* 无内部状态保留。 2508* 通过ffrt_submit_base()接口以异步任务方式提交函数执行。 2509* 将函数访问的数据对象以及访问方式在ffrt_submit_base()接口中的in_deps/out_deps参数表达。 2510* 程序员通过inDeps/outDeps参数表达任务间依赖关系以保证程序执行的正确性。 2511 2512> 做到纯函数的好处在于:1. 能够最大化挖掘并行度,2.避免DataRace和锁的问题。 2513 2514 2515 2516**在实际中,可以根据场景放松纯函数的约束,但前提是:** 2517 2518* 确定添加的in_deps/out_deps可确保程序正确执行。 2519* 通过FFRT提供的锁机制保护对全局变量的访问。 2520 2521 2522### 建议2: 使用FFRT提供的替代API 2523 2524* 禁止在FFRT任务中使用系统线程库API创建线程,使用submit提交任务。 2525* 使用FFRT提供的锁,条件变量,睡眠,IO等API代替系统线程库API。 2526 * 使用系统线程库API可能造成工作线程阻塞,引起额外性能开销。 2527 2528 2529 2530### 建议3: Deadline机制 2531 2532* **必须用于具备周期/重复执行特征的处理流程。** 2533* 在有明确时间约束和性能关键的处理流程中使用,避免滥用。 2534* 在相对大颗粒度的处理流程中使用,例如具有16.6ms时间约束的帧处理流程。 2535 2536 2537 2538### 建议4: 从线程模型迁移 2539 2540* 创建线程替代为创建FFRT任务。 2541 * 线程从逻辑上类似无in_deps的任务。 2542* 识别线程间的依赖关系,并将其表达在任务的依赖关系in_deps/out_deps上。 2543* 线程内计算过程分解为异步任务调用。 2544* 通过任务依赖关系和锁机制避免并发任务数据竞争问题。 2545 2546 2547 2548### 建议5: 推荐使用C++接口 2549 2550* FFRT的C++接口是基于C接口实现,在使用API接口时可以手动添加C++相关头文件后配套使用。 2551* 相关C++接口下载参考:[FFRT C++接口](https://gitee.com/openharmony/resourceschedule_ffrt/tree/master/interfaces/kits) 2552 2553 2554 2555 2556 2557## 已知限制 2558 2559 2560### C API中初始化ffrt对象后,对象的置空与销毁由用户负责 2561 2562* 为保证较高的性能,ffrt的C API中内部不包含对对象的销毁状态的标记,用户需要合理地进行资源的释放,重复调用各个对象的destroy操作,其结果是未定义的。 2563* 错误示例1,重复调用destroy可能造成不可预知的数据损坏。 2564 2565```{.c} 2566#include "ffrt.h" 2567void abnormal_case_1() 2568{ 2569 ffrt_task_handle_t h = ffrt_submit_h_base([](){printf("Test task running...\n");}, NULL, NULL, NULL, NULL, NULL); 2570 ... 2571 ffrt_task_handle_destroy(h); 2572 ffrt_task_handle_destroy(h); // double free 2573} 2574``` 2575 2576* 错误示例2,未调用destroy会造成内存泄漏 2577 2578```{.c} 2579#include "ffrt.h" 2580void abnormal_case_2() 2581{ 2582 ffrt_task_handle_t h = ffrt_submit_h_base([](){printf("Test task running...\n");}, NULL, NULL, NULL, NULL, NULL); 2583 ... 2584 // memory leak 2585} 2586``` 2587 2588* 建议示例,仅调用一次destroy,如有必要可进行置空 2589 2590```{.c} 2591#include "ffrt.h" 2592void normal_case() 2593{ 2594 ffrt_task_handle_t h = ffrt_submit_h_base([](){printf("Test task running...\n");}, NULL, NULL, NULL, NULL, NULL); 2595 ... 2596 ffrt_task_handle_destroy(h); 2597 h = nullptr; // if necessary 2598} 2599``` 2600