IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SylixOS中的线程【23】--- 线程条件变量 -> 正文阅读

[Java知识库]SylixOS中的线程【23】--- 线程条件变量

概念

放锁与阻塞

有十个线程(thread0~9)和一个变量 V,thread0 需要写变量 V,thread1 ~ 9 需要读变量 V。我们假设只有在变量 V 的值改变时,读线程才需要读变量 V,在变量 V的值不变时,读者线程需要阻塞。

读线程阻塞前可能需要一种“判断”操作,判断变量 V 当前的值是否与上一次读到的值不一致;“判断”操作前需要加锁,如果一致那么读线程需要阻塞,阻塞前又需要释放该锁,释放锁与阻塞需要是一个不可打断的原子操作。我们可以想象一下,如果释放锁与阻塞不是一个原子操作,如果读线程在释放锁与阻
塞之间被thread0 抢占了,thread0可以成功获锁并改写变量 V,同时在thread0要以广播的方式通知多个读线程去读该变量。但变量 V 的值改变了读线程却阻塞了,显然读线程丢失了一次对变量 V 值改变的响应!

我们需要一种新的线程间通信手段来解决以上问题:释放锁与阻塞是一个原子操作和能以广播的方式通知多个读者线程。

线程条件变量

条件变量是多线程间的一种同步机制,能很好的解决以上问题。条件变量与互斥锁一起使用时,允许线程以无竞争的形式等待条件的发生。条件本身由互斥量保护,因此线程在改变条件之前必须首先锁住互斥量,其他线程在获得互斥量之前不会察觉到条件的改变。

SylixOS 条件变量的类型为 LW_THREAD_COND,使用时需要定义一个 该类型的变量。一个 SylixOS 条件变量必须要调用 Lw_Thread_Cond_Init 函数初始化之后才能使用。如果需要等待一个条件变量,可以调用 Lw_Thread_Cond_Wait 函数,中断服务程序不能调用 Lw_Thread_Cond_Wait 函数等待一个条件变量,因为 Lw_Thread_Cond_Wait 函数会阻塞当前线程。发送一个条件变量可以使用 Lw_Thread_Cond_Signal 或 Lw_Thread_Cond_Broadcast 函 数,中断服务程序也可以发送一个条件变量。当一个条件变量使用完毕后,应该调用 Lw_Thread_Cond_Destroy 函数删除,SylixOS会回收该条件变量占用的内核资源。需要注意的是,尝试再次使用一个已被删除的条件变量将会产生未知错误。

创建一个 SylixOS 条件变量需要使用 SylixOS 条件变量属性块。SylixOS 条件变量属性块的类型为 ULONG。属性有两种共享(LW_THREAD_PROCESS_SHARED)和私有(LW_THREAD_PROCESS_PRIVATE)。

接口

条件变量属性块操作接口

#define LW_THREAD_PROCESS_SHARED        0x1
#define LW_THREAD_PROCESS_PRIVATE       0x0
/*********************************************************************************************************
** 函数名称: API_ThreadCondAttrInit
** 功能描述: 初始化一个条件变量属性控制块.
** 输 入  : pulAttr            属性
** 输 出  : ERROR CODE
*********************************************************************************************************/
ULONG  API_ThreadCondAttrInit (ULONG  *pulAttr)
/*********************************************************************************************************
** 函数名称: API_ThreadCondAttrDestroy
** 功能描述: 销毁一个条件变量属性控制块.
** 输 入  : pulAttr            属性
** 输 出  : ERROR CODE
*********************************************************************************************************/
ULONG  API_ThreadCondAttrDestroy (ULONG  *pulAttr)
/*********************************************************************************************************
** 函数名称: API_ThreadCondAttrSetPshared
** 功能描述: 设置一个条件变量属性控制块的共享属性.
** 输 入  : pulAttr            属性
**           iShared            共享属性
** 输 出  : ERROR CODE
*********************************************************************************************************/
ULONG  API_ThreadCondAttrSetPshared (ULONG  *pulAttr, INT  iShared)
/*********************************************************************************************************
** 函数名称: API_ThreadCondAttrGetPshared
** 功能描述: 获得一个条件变量属性控制块的共享属性.
** 输 入  : pulAttr            属性
**           piShared           共享属性
** 输 出  : ERROR CODE
*********************************************************************************************************/
ULONG  API_ThreadCondAttrGetPshared (const ULONG  *pulAttr, INT  *piShared)

条件变量操作接口

/*********************************************************************************************************
** 函数名称: API_ThreadCondInit
** 功能描述: 初始化一个条件变量控制块.
** 输 入  : ptcd              条件变量控制块
**           ulAttr            控制属性 (当前忽略, 主要用作进程共享处理)
** 输 出  : ERROR CODE
*********************************************************************************************************/
ULONG  API_ThreadCondInit (PLW_THREAD_COND  ptcd, ULONG  ulAttr)
/*********************************************************************************************************
** 函数名称: API_ThreadCondDestroy
** 功能描述: 销毁一个条件变量控制块.
** 输 入  : ptcd              条件变量控制块
** 输 出  : ERROR CODE
*********************************************************************************************************/
ULONG  API_ThreadCondDestroy (PLW_THREAD_COND  ptcd)
/*********************************************************************************************************
** 函数名称: API_ThreadCondSignal
** 功能描述: 向等待条件变量的线程发送信号.
** 输 入  : ptcd              条件变量控制块
** 输 出  : ERROR CODE
*********************************************************************************************************/
ULONG  API_ThreadCondSignal (PLW_THREAD_COND  ptcd)
/*********************************************************************************************************
** 函数名称: API_ThreadCondBroadcast
** 功能描述: 向所有等待条件变量的线程发送信号.
** 输 入  : ptcd              条件变量控制块
** 输 出  : ERROR CODE
*********************************************************************************************************/
LW_API  
ULONG  API_ThreadCondBroadcast (PLW_THREAD_COND  ptcd)
/*********************************************************************************************************
** 函数名称: API_ThreadCondWait
** 功能描述: 等待条件变量.
** 输 入  : ptcd              条件变量控制块
**           ulMutex           互斥信号量
**           ulTimeout         超时时间
** 输 出  : ERROR CODE
*********************************************************************************************************/
ULONG  API_ThreadCondWait (PLW_THREAD_COND  ptcd, LW_OBJECT_HANDLE  ulMutex, ULONG  ulTimeout)

用法

#include <stdio.h>
#include <SylixOS.h>

static INT              _G_iCount = 0;
static LW_HANDLE        _G_hLock;
static LW_THREAD_COND   _G_threadCond;

static PVOID tTestR (PVOID pvArg)
{
    INT iError;

    while (1) {
        iError = Lw_SemaphoreM_Wait(_G_hLock, LW_OPTION_WAIT_INFINITE);
        if (iError != ERROR_NONE) {
            break;
        }

        iError = Lw_Thread_Cond_Wait(&_G_threadCond, _G_hLock, LW_OPTION_WAIT_INFINITE);
        if (iError != ERROR_NONE) {
            Lw_SemaphoreM_Post(_G_hLock);
            break;
        }

        printf("tTestR(%d): count = %d\n", (INT)pvArg, _G_iCount);
        Lw_SemaphoreM_Post(_G_hLock);
    }

    return (LW_NULL);
}

static PVOID tTestW (PVOID pvArg)
{
    INT iError;

    while (1) {
        iError = Lw_SemaphoreM_Wait(_G_hLock, LW_OPTION_WAIT_INFINITE);
        if (iError != ERROR_NONE) {
            break;
        }

        _G_iCount++;
        printf("tTestW(): count = %d\n", _G_iCount);
        Lw_Thread_Cond_Broadcast(&_G_threadCond);

        Lw_SemaphoreM_Post(_G_hLock);
        Lw_Time_SSleep(1);

        if (_G_iCount == 3) {
            break;
        }
    }

    return (LW_NULL);
}

int main (int argc, char *argv[])
{
    LW_CLASS_THREADATTR  hThreadAttr = API_ThreadAttrGetDefault();
    LW_HANDLE   hThreadRId[3];
    LW_HANDLE   hThreadWId;
    ULONG       ulCondAttr;
    INT         iError;
    INT         i;

    Lw_Thread_Condattr_Init(&ulCondAttr);
    Lw_Thread_Condattr_Setpshared(&ulCondAttr, LW_FALSE);

    iError = Lw_Thread_Cond_Init(&_G_threadCond, ulCondAttr);
    if (iError != ERROR_NONE) {
        printf("cond create failed.\n");
        return (-1);
    }
    Lw_Thread_Condattr_Destroy(&ulCondAttr);

    _G_hLock = Lw_SemaphoreM_Create("count_lock",
                                    LW_PRIO_HIGH,
                                    LW_OPTION_WAIT_FIFO |
                                    LW_OPTION_OBJECT_LOCAL|
                                    LW_OPTION_INHERIT_PRIORITY |
                                    LW_OPTION_ERRORCHECK,
                                    LW_NULL);
    if (_G_hLock == LW_OBJECT_HANDLE_INVALID) {
        printf("mutex create failed.\n");
        return (-1);
    }

    for (i = 0; i < 3; i++) {
        hThreadAttr.THREADATTR_pvArg = (PVOID)i;
        hThreadRId[i] = Lw_Thread_Create("t_testr", tTestR, &hThreadAttr, LW_NULL);
        if (hThreadRId[i] == LW_OBJECT_HANDLE_INVALID) {
            printf("t_testr create failed.\n");
            return (-1);
        }
    }

    hThreadWId = Lw_Thread_Create("t_testw", tTestW, LW_NULL, LW_NULL);
    if (hThreadWId == LW_OBJECT_HANDLE_INVALID) {
        printf("t_testw create failed.\n");
        return (-1);
    }

    Lw_Thread_Join(hThreadWId, LW_NULL);

    Lw_Thread_Cond_Destroy(&_G_threadCond);
    Lw_SemaphoreM_Delete(&_G_hLock);

    return (0);
 }
[root@sylixos:/root]# 
[root@sylixos:/root]# 
[root@sylixos:/root]# /apps/sylixosAppExample/srcSylixos/threadCond
tTestW(): count = 1
tTestR(0): count = 1
tTestR(1): count = 1
tTestR(2): count = 1
tTestW(): count = 2
tTestR(0): count = 2
tTestR(1): count = 2
tTestR(2): count = 2
tTestW(): count = 3
tTestR(0): count = 3
tTestR(1): count = 3
tTestR(2): count = 3
[root@sylixos:/root]# 
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-21 20:35:37  更:2022-03-21 20:37:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:40:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码