1、文档名称 文档密级2019-5-25 华为机密,未经许可不得扩散 第 1 页, 共 3 页1 临界区不 论 是 硬 件 临 界 资 源 , 还 是 软 件 临 界 资 源 , 多 个 进 程 必 须 互 斥 地 对 它 进 行 访 问 。 每个 进 程 中 访 问 临 界 资 源 的 那 段 代 码 称 为 临 界 区 ( Critical Section) 。 每 个 进 程 中 访 问 临 界 资 源 的 那 段 程 序 称 为 临 界 区 ( Critical Section) ( 临 界 资源 是 一 次 仅 允 许 一 个 进 程 使 用 的 共 享 资 源 ) 。 每 次 只 准
2、许 一 个 进 程 进 入 临 界 区 , 进 入 后不 允 许 其 他 进 程 进 入 。 不 论 是 硬 件 临 界 资 源 , 还 是 软 件 临 界 资 源 , 多 个 进 程 必 须 互 斥 地对 它 进 行 访 问 。多 个 进 程 中 涉 及 到 同 一 个 临 界 资 源 的 临 界 区 称 为 相 关 临 界 区 。 进 程 进 入 临 界 区 的 调 度 原 则 是 : 如 果 有 若 干 进 程 要 求 进 入 空 闲 的 临 界 区 , 一次 仅 允 许 一 个 进 程 进 入 。 任 何 时 候 , 处 于 临 界 区 内 的 进 程 不 可 多 于 一 个 。 如
3、已 有 进程 进 入 自 己 的 临 界 区 , 则 其 它 所 有 试 图 进 入 临 界 区 的 进 程 必 须 等 待 。 进 入 临 界 区 的进 程 要 在 有 限 时 间 内 退 出 , 以 便 其 它 进 程 能 及 时 进 入 自 己 的 临 界 区 。 如 果 进 程 不 能进 入 自 己 的 临 界 区 , 则 应 让 出 CPU, 避 免 进 程 出 现 “忙 等 ”现 象 。如 果 有 多 个 线 程 试 图 同 时 访 问 临 界 区 , 那 么 在 有 一 个 线 程 进 入 后 其 他 所 有 试 图 访 问此 临 界 区 的 线 程 将 被 挂 起 , 并 一
4、直 持 续 到 进 入 临 界 区 的 线 程 离 开 。 临 界 区 在 被 释 放 后 ,其 他 线 程 可 以 继 续 抢 占 , 并 以 此 达 到 用 原 子 方 式 操 作 共 享 资 源 的 目 的 。临 界 区 在 使 用 时 以 CRITICAL_SECTION 结 构 对 象 保 护 共 享 资 源 , 并 分 别 用 EnterCriticalSection( ) 和 LeaveCriticalSection( ) 函 数 去 标 识 和 释 放 一 个 临 界 区 。 所用 到 的 CRITICAL_SECTION 结 构 对 象 必 须 经 过 InitializeC
5、riticalSection( ) 的 初 始化 后 才 能 使 用 , 而 且 必 须 确 保 所 有 线 程 中 的 任 何 试 图 访 问 此 共 享 资 源 的 代 码 都 处 在 此 临界 区 的 保 护 之 下 。 否 则 临 界 区 将 不 会 起 到 应 有 的 作 用 , 共 享 资 源 依 然 有 被 破 坏 的 可 能 。下 面 通 过 一 段 代 码 展 示 了 临 界 区 在 保 护 多 线 程 访 问 的 共 享 资 源 中 的 作 用 。 通 过 两 个线 程 来 分 别 对 全 局 变 量 g_cArray10进 行 写 入 操 作 , 用 临 界 区 结 构
6、对 象 g_cs 来 保 持线 程 的 同 步 , 并 在 开 启 线 程 前 对 其 进 行 初 始 化 。 为 了 使 实 验 效 果 更 加 明 显 , 体 现 出 临 界区 的 作 用 , 在 线 程 函 数 对 共 享 资 源 g_cArray10的 写 入 时 , 以 Sleep( ) 函 数 延 迟1 毫 秒 , 使 其 他 线 程 同 其 抢 占 CPU 的 可 能 性 增 大 。 如 果 不 使 用 临 界 区 对 其 进 行 保 护 ,则 共 享 资 源 数 据 将 被 破 坏 ( 参 见 图 1( a) 所 示 计 算 结 果 ) , 而 使 用 临 界 区 对 线 程
7、保 持同 步 后 则 可 以 得 到 正 确 的 结 果 ( 参 见 图 1( b) 所 示 计 算 结 果 ) 。 代 码 实 现 清 单 附 下 :/ 临 界 区 结 构 对 象CRITICAL_SECTION g_cs;/ 共 享 资 源 char g_cArray10;UINT ThreadProc10(LPVOID pParam)/ 进 入 临 界 区EnterCriticalSection(/ 对 共 享 资 源 进 行 写 入 操 作文档名称 文档密级2019-5-25 华为机密,未经许可不得扩散 第 2 页, 共 3 页for (int i = 0; i 10; i+)g_cA
8、rray = a;Sleep(1);/ 离 开 临 界 区LeaveCriticalSection(return 0;UINT ThreadProc11(LPVOID pParam)/ 进 入 临 界 区EnterCriticalSection(/ 对 共 享 资 源 进 行 写 入 操 作for (int i = 0; i 10; i+)g_cArray10 - i - 1 = b;Sleep(1);/ 离 开 临 界 区LeaveCriticalSection(return 0;void CSample08View:OnCriticalSection() / 初 始 化 临 界 区Init
9、ializeCriticalSection(/ 启 动 线 程AfxBeginThread(ThreadProc10, NULL);AfxBeginThread(ThreadProc11, NULL);/ 等 待 计 算 完 毕Sleep(300);/ 报 告 计 算 结 果CString sResult = CString(g_cArray);AfxMessageBox(sResult); 文档名称 文档密级2019-5-25 华为机密,未经许可不得扩散 第 3 页, 共 3 页在 使 用 临 界 区 时 , 一 般 不 允 许 其 运 行 时 间 过 长 , 只 要 进 入 临 界 区 的
10、 线 程 还 没 有 离 开, 其 他 所 有 试 图 进 入 此 临 界 区 的 线 程 都 会 被 挂 起 而 进 入 到 等 待 状 态 , 并 会 在 一 定 程 度 上影 响 程 序 的 运 行 性 能 。 尤 其 需 要 注 意 的 是 不 要 将 等 待 用 户 输 入 或 是 其 他 一 些 外 界 干 预 的操 作 包 含 到 临 界 区 。 如 果 进 入 了 临 界 区 却 一 直 没 有 释 放 , 同 样 也 会 引 起 其 他 线 程 的 长 时间 等 待 。 换 句 话 说 , 在 执 行 了 EnterCriticalSection( ) 语 句 进 入 临 界 区 后 无 论 发 生 什么 , 必 须 确 保 与 之 匹 配 的 LeaveCriticalSection( ) 都 能 够 被 执 行 到 。 可 以 通 过 添 加结 构 化 异 常 处 理 代 码 来 确 保 LeaveCriticalSection( ) 语 句 的 执 行 。 虽 然 临 界 区 同 步速 度 很 快 , 但 却 只 能 用 来 同 步 本 进 程 内 的 线 程 , 而 不 可 用 来 同 步 多 个 进 程 中 的 线 程 。