推荐星级:
  • 1
  • 2
  • 3
  • 4
  • 5

RT-Thread快速入门-线程间同步之信号量

更新时间:2023-10-03 07:05:25 大小:325K 上传用户:sun2152查看TA发布的资源 标签:RT-Thread 下载积分:1分 评价赚积分 (如何评价?) 打赏 收藏 评论(0) 举报

资料介绍

线 程 同 步 是 指 多 个 线 程 通 过 某 种 特 定 的 机 制 ,来 控 制 线 程 之 间 的 先 后 执 行 顺 序 。 RT-Thread 提 供 了 一 种 线 程 同 步 的 方 式 : 信 号 量 ( semaphore) 、 互 斥 量( mutex)、和 事 件 集( event)。本 篇 文 章 主 要 介 绍 信 号 量 相 关 的 内 容 。 信 号 量 的 工 作 机 制 信 号 量 是 一 种 可 以 用 来 解 决 线 程 间 同 步 问 题 的 内 核 对 象 ,线 程 通 过 获 取 和 释 放 信 号 量 , 来 达 到 同 步 的 目 的 。 每 个 信 号 量 对 象 都 有 一 个 信 号 量 值 和 一 个 线 程 等 待 队 列 ,信 号 量 的 值 表 示 信 号 对 象 的 实 例 数 目 或 者 资 源 数 目 ;线 程 等 待 队 列 ,由 等 待 获 取 当 前 信 号 量 的 线 程 按 照 某 种 顺 序 排 列 而 成 。 当 信 号 量 值 为 零 时 ,再 申 请 该 信 号 量 的 线 程 就 会 被 挂 起 在 该 信 号 量 的 等 待 队 列 上 , 等 待 可 用 的 信 号 量 资 源 。 信 号 量 控 制 块 信 号 量 控 制 块 是 RT-Thread 用 于 管 理 信 号 量 的 一 个 数 据 结 构 ,信 号 量 控 制 块 的 结 构 体 struc t rt_semaphore 定 义 如 下 ,rt_sem_t 表 示 信 号 量 的 句 柄 , 即 指 向 信 号 量 控 制 块 的 指 针 。 struct rt_semaphore { struct rt_ipc_object parent; /* 继承自 ipc_object 类 */ rt_uint16_t value; /* 信号量的值 */ rt_uint16_t reserved; /* 保留域 */ }; /* rt_sem_t 为指向 rt_semaphore 结构体的指针类型 */ typedef struct rt_semaphore *rt_sem_t; struc t rt_semaphore 从 rt_ipc_objec t 派 生 而 来 , 由 IPC 容 器 管 理 , 信 号 量 的 最 大 值 为 65535。 结 构 体 struc t rt_ipc_objec t parent 定 义 如 下 : struct rt_object { char name[RT_NAME_MAX]; /* 内核对象名称 */ rt_uint8_t type; /* 内核对象类型 */ rt_uint8_t flag; /* 内核对象的参数 */ #ifdef RT_USING_MODULE void *module_id; /* 应用程序模块 ID */ #endif rt_list_t list; /* 内核对象管理链表 */ }; struct rt_ipc_object { struct rt_object parent; /* 继承自 rt_object */ rt_list_t suspend_thread; /* 挂起的线程链表 */ }; 信 号 量 控 制 块 中 含 有 信 号 量 相 关 的 重 要 参 数 ,在 信 号 量 各 种 状 态 之 间 起 到 纽 带 的 作 用 。 接 下 来 看 看 如 何 对 一 个 信 号 量 进 行 操 作 。 管 理 信 号 量 RT-Thread 提 供 了 一 系 列 的 函 数 接 口 , 用 于 对 信 号 量 进 行 操 作 。 包 括 :  创 建 /初 始 化 信 号 量   获 取 信 号 量   释 放 信 号 量   删 除 /脱 离 信 号 量  常 用 的 信 号 量 操 作 为 :创 建 信 号 量 、获 取 信 号 量 、释 放 信 号 量 。下 面 重 点 介 绍 这 三 种 操 作 。 1. 创 建 信 号 量 RT-Thread 创 建 信 号 量 两 种 方 式 : 动 态 创 建 和 静 态 初 始 化 。 跟 其 他 内 核 对 象 类 似 , 动 态 创 建 是 由 内 核 负 责 分 配 信 号 量 控 制 块 , 然 后 对 其 进 行 基 本 的 初 始 化 工 作 。静 态 方 式 创 建 ,是 由 用 户 负 责 定 义 一 个 信 号 量 控 制 块 结 构 体 变 量 ,然 后 调 用 初 始 化 函 数 对 其 进 行 初 始 化 工 作 。 动 态 创 建 信 号 量 的 函 数 接 口 如 下 : rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag) 当 调 用 这 个 函 数 时 , 系 统 将 先 从 对 象 管 理 器 中 分 配 一 个 semaphore 对 象 , 并 初 始 化 这 个 对 象 , 然 后 初 始 化 父 类 IPC 对 象 以 及 与 semaphore 相 关 的 部 分 。 该 函 数 的 各 个 参 数 解 释 如 下 : 参 数 描 述 name 信 号 量 名 称 value 信 号 量 的 初 始 值 flag 创 建 信 号 量 的 标 志 信 号 量 创 建 成 功 ,则 返 回 信 号 量 控 制 块 的 指 针 。创 建 失 败 ,则 返 回 RT_NULL。 参 数 flag 的 作 用 是 ,当 信 号 量 不 可 用 时 ,多 个 线 程 等 待 的 排 队 方 式 。 这 个 参 数 取 值 有 两 种 :  RT_IPC_FLAG_FIFO, 先 进 先 出 方 式 。 等 待 信 号 量 的 线 程 按 照 先 进 先 出 的 方 式 排 队 , 先 进 入 的 线 程 将 先 获 得 等 待 的 信 号 量 。   RT_IPC_FLAG_PRIO, 优 先 级 等 待 方 式 。 等 待 信 号 量 的 线 程 按 照 优 先 级 进 行 排 队 , 优 先 级 高 的 等 待 线 程 将 先 获 得 等 待 的 信 号 量 。  静 态 方 式 创 建 信 号 量 , 需 要 先 定 义 一 个 信 号 量 控 制 块 结 构 struc t rt_semaphore 类 型 的 变 量 , 然 后 使 用 如 下 函 数 对 其 进 行 初 始 化 : rt_err_t rt_sem_init(rt_sem_t sem, const char *name, rt_uint32_t value, rt_uint8_t flag) 这 个 函 数 参 数 , 除 了 sem , 其 他 参 数 跟 动 态 创 建 信 号 量 函 数 rt_sem_create() 的 参 数 相 同 。 参 数 sem 为 信 号 量 控 制 块 的 指 针 , 指 向 用 户 定 义 的 struc t rt_semaphore 结 构 变 量 的 地 址 。 rt_sem_init() 函 数 的 主 要 作 用 是 , 对 sem 指 向 的 信 号 量 控 制 块 进 行 初 始 化 操 作 。 该 函 数 的 返 回 值 为 RT_EOK。 2. 获 取 信 号 量 线 程 通 过 获 取 信 号 量 来 获 得 信 号 量 资 源 实 例 ,当 信 号 量 值 大 于 零 时 , 线 程 将 获 得 信 号 量 ,并 且 相 应 的 信 号 量 值 会 减 1。如 果 信 号 量 的 值 为 零 , 说 明 当 前 信 号 量 资 源 不 可 用 , 线 程 会 获 取 失 败 。 RT-Thread 中 获 取 信 号 量 的 函 数 如 下 : rt_err_t rt_sem_take (rt_sem_t sem, rt_int32_t time) 参 数 sem 表 示 信 号 量 控 制 块 指 针 ( 信 号 量 的 句 柄 ) 。 参 数 time 表 示 线 程 等 待 获 取 信 号 量 的 时 间 , 单 位 是 系 统 时 钟 节 拍 。 调 用 此 函 数 获 取 信 号 量 时 , 如 果 信 号 量 的 值 为 零 , 线 程 将 根 据 time 参 数 的 情 况 会 有 不 同 的 动 作 :  参 数 值 为 零 , 则 函 数 会 直 接 返 回 。   参 数 值 不 为 零 , 则 会 等 待 设 定 的 时 间 。   参 数 值 为 最 大 时 钟 节 拍 数 ,则 会 永 久 等 待 ,直 到 其 他 线 程 或 中 断 释 放 该 信 号 量 。  如 果 在 参 数 time 指 定 的 时 间 内 没 有 获 取 到 信 号 量 ,线 程 将 超 时 返 回 , 返 回 值 为 -RT_ETIMEOUT。 rt_sem_take() 函 数 返 回 RT_EOK , 表 示 成 功 获 得 信 号 量 。 返 回 -RT_ERROR , 表 示 其 他 错 误 。 线 程 获 取 信 号 量 不 可 以 用 时 , 且 等 待 时 间 time 不 为 零 , 3. 释 放 信 号 量 释 放 信 号 量 的 系 统 函 数 如 下 : rt_err_t rt_sem_release(rt_sem_t sem) 参 数 sem 表 示 信 号 量 控 制 块 指 针 ( 信 号 量 的 句 柄 ) 。 释 放 信 号 量 操 作 , 根 据 具 体 情 况 , 会 有 两 种 结 果 :  如 果 有 线 程 等 待 获 取 这 个 信 号 量 时 ,释 放 信 号 量 将 唤 醒 等 待 队 列 中 的 第 一 个 线 程 , 由 它 获 取 信 号 量 , 信 号 量 的 值 仍 然 为 零 。   如 果 没 有 线 程 等 待 获 取 信 号 量 , 则 信 号 量 的 值 将 会 加 1。  实 战 演 练 绝 知 此 事 要 躬 行 。 通 过 具 体 的 实 例 ,来 看 看 如 何 使 用 RT-Thread 的 信 号 量 操 作 函 数 。 动 态 创 建 一 个 信 号 量 ,创 建 两 个 线 程 ,一 个 线 程 释 放 信 号 量 ,一 个 线 程 获 取 信 号 量 后 , 执 行 后 续 的 动 作 。 #include #define THREAD_PRIORITY 25 #define THREAD_TIMESLICE 5 /* 指向信号量的指针 */ static rt_sem_t dynamic_sem = RT_NULL; /* 线程 1 入口函数 */ static void rt_thread1_entry(void *parameter) { static rt_uint8_t count = 0; while(1) { if(count <= 100) { count++; } else { return; } /* count 每计数 10 次, 就释放一次信号量 */ if(0 == (count % 10)) { rt_kprintf("thread1 release a dynamic semaphore.\n"); rt_sem_release(dynamic_sem); } /* 延迟一会儿 */ rt_thread_delay(10); } } /* 线程 2 入口函数 */ static void rt_thread2_entry(void *parameter) { static rt_err_t result; static rt_uint8_t number = 0; while(1) { /* 永久方式等待信号量, 获取到信号量,则执行 number 自加的操作 */ result = rt_sem_take(dynamic_sem, RT_WAITING_FOREVER); if (result != RT_EOK) { rt_kprintf("thread2 take a dynamic semaphore, failed.\n"); rt_sem_delete(dynamic_sem); return; } else { number++; rt_kprintf("thread2 take a dynamic semaphore. number = %d\n " ,number); } rt_thread_delay(10); } } int main(void) { /* 线程控制块指针 */ rt_thread_t thread1 = RT_NULL; rt_thread_t thread2 = RT_NULL; /* 创建一个动态信号量,初始值是 0 */ dynamic_sem = rt_sem_create("dsem", 0, RT_IPC_FLAG_FIFO); if (dynamic_sem == RT_NULL) { rt_kprintf("create dynamic semaphore failed.\n"); return -1; } else { rt_kprintf("create done. dynamic semaphore value = 0.\n"); } /* 动态创建线程 1 */ thread1 = rt_thread_create("thread1", rt_thread1_entry, RT_NULL, 1024, THREAD_PRIORITY, THREAD_TIMESLICE); if(thread1 != RT_NULL) { /* 启动线程 */ rt_thread_startup(thread1); } /* 动态创建线程 2 */ thread2 = rt_thread_create("thread2", rt_thread2_entry, RT_NULL, 1024, THREAD_PRIORITY-1, THREAD_TIMESLICE); if(thread2 != RT_NULL) { /* 启动线程 */ rt_thread_startup(thread2); } return 0; } 线 程 1 在 count 计 数 为 10 的 倍 数 时 ,释 放 一 个 信 号 量 ,线 程 2 在 接 收 到 信 号 量 后 ,对 number 进 行 加 1 操 作 。程 序 运 行 结 果 如 下 所 示 :

部分文件列表

文件名 大小
RT-Thread快速入门-线程间同步之信号量.pdf 325K

【关注B站账户领20积分】

全部评论(0)

暂无评论

上传资源 上传优质资源有赏金

  • 打赏
  • 30日榜单
  • sd-hyc 打赏1.00元   1天前

    资料:神州易刻2024最新版

  • 柏涵 打赏1.00元   3天前

    资料:XDS100_v1_1_RTM

  • 21ic下载 打赏310.00元   3天前

    用户:jh0355

  • 21ic下载 打赏310.00元   3天前

    用户:w178191520

  • 21ic下载 打赏210.00元   3天前

    用户:gsy幸运

  • 21ic下载 打赏210.00元   3天前

    用户:zhengdai

  • 21ic下载 打赏210.00元   3天前

    用户:jh03551

  • 21ic下载 打赏110.00元   3天前

    用户:liqiang9090

  • 21ic下载 打赏60.00元   3天前

    用户:sun2152

  • 21ic下载 打赏60.00元   3天前

    用户:xuzhen1

  • 21ic下载 打赏80.00元   3天前

    用户:xzxbybd

  • 21ic下载 打赏25.00元   3天前

    用户:WK520077778

  • 21ic下载 打赏20.00元   3天前

    用户:w1966891335

  • 21ic下载 打赏20.00元   3天前

    用户:铁蛋锅

  • 21ic下载 打赏20.00元   3天前

    用户:玉落彼岸

  • 21ic下载 打赏15.00元   3天前

    用户:kk1957135547

  • 21ic下载 打赏10.00元   3天前

    用户:zpf22332

  • 21ic下载 打赏5.00元   3天前

    用户:pangpidan

  • 21ic下载 打赏5.00元   3天前

    用户:hpxny

  • 21ic下载 打赏5.00元   3天前

    用户:pandq2009

  • 21ic下载 打赏5.00元   3天前

    用户:tomp

推荐下载