RT_thread(四)线程间同步之信号量

本文详细介绍了线程间同步的概念,重点讲解了信号量的机制、控制块、管理方式,并提供了具体的创建、删除、获取和释放信号量的示例。通过停车场的例子帮助理解信号量的工作原理,展示了如何在RT-Thread实时系统中使用信号量实现线程同步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


线程间同步

在多线程实时系统中,一项工作的完成往往可以通过多个线程协调的方式共同来完成,而通过这三种方式:信号量、互斥量、事件集可以保证多个线程之间同步。
线程的同步方式有很多种,其核心思想都是:在访问临界区的时候只允许一个 (或一类) 线程运行。进入 / 退出临界区的方式有很多种:
1)调用 rt_hw_interrupt_disable() 进入临界区,调用 rt_hw_interrupt_enable() 退出临界区;详见《中断管理》的全局中断开关内容。
2)调用 rt_enter_critical() 进入临界区,调用 rt_exit_critical() 退出临界区。


线程同步是指多个线程通过特定的机制(如互斥量,事件对象,临界区)来控制线程之间的执行顺序

1.信号量

以生活中的停车场为例来理解信号量的概念:

①当停车场空的时候,停车场的管理员发现有很多空车位,此时会让外面的车陆续进入停车场获得停车位;

②当停车场的车位满的时候,管理员发现已经没有空车位,将禁止外面的车进入停车场,车辆在外排队等候;

③当停车场内有车离开时,管理员发现有空的车位让出,允许外面的车进入停车场;待空车位填满后,又禁止外部车辆进入。

在此例子中,管理员就相当于信号量,管理员手中空车位的个数就是信号量的值(非负数,动态变化);停车位相当于公共资源(临界区),车辆相当于线程。车辆通过获得管理员的允许取得停车位,就类似于线程通过获得信号量访问公共资源。

1.信号量机制

信号量是一种轻型的用于解决线程间同步问题的内核对象,线程可以获取或释放它,从而达到同步或互斥的目的。

2.信号量控制块

信号量控制块是操作系统用于管理信号量的一个数据结构

struct rt_semaphore
{
   
    struct rt_ipc_object parent; //继承ipc_object结构体{rt_object(name、type、flag); suspend_thread}            

    rt_uint16_t          value;     //信号量的数值(例如空车位数量)
};
typedef struct rt_semaphore *rt_sem_t;

在这里插入图片描述
第一个parent rt_ipc_object
{struct rt_object parent;
rt_list_t suspend_thread;
}
第二个parent rt_object
{
char name[RT_NAME_MAX];
rt_uint8_t type;
rt_uint8_t flag;
}

3.信号量管理方式

Kernel中的 ipc.c

在这里插入图片描述

函数顺序按照ipc.c中顺序(内核代码顺序是按照创作顺序书写的)

1.判断是否使用信号量

#ifdef RT_USING_SEMAPHORE

信号量的开端,在rtconfig.h中是否宏定义了,才可使用信号量函数(一般都是定义的)

2.初始化和脱离

初始化(多是对系统静态句柄操作)

rt_err_t rt_sem_init(rt_sem_t    sem,//信号量对象的句柄(停车场地址)
                     const char *name,//信号量名称(停车场名字)
                     rt_uint32_t value,//信号量初始值(停车场车位数量)
                     rt_uint8_t  flag)//信号量标志等待线程队列RT_IPC_FLAG_FIFO(按顺序) 或 RT_IPC_FLAG_PRIO(按优先级)(排队顺序还是优先级顺序进出)
{
   
    RT_ASSERT(sem != RT_NULL);//信号量对象的句柄是否存在

    /* init object */
    rt_object_init(&(sem->parent.parent), RT_Object_Class_Semaphore, name);
    //sem->parent.parent的初始化(见1.2信号量控制块)

    /* init ipc object */
    rt_ipc_object_init(&(sem->parent));
    //sem->parent的初始化(见1.2信号量控制块)

    /* set init value */
    sem->value = value;//赋值

    /* set parent */
    sem->parent.parent.flag = flag;//设置标志位RT_IPC_FLAG_FIFO(按顺序) 或 RT_IPC_FLAG_PRIO(按优先级)

    return RT_EOK;
}
RTM_EXPORT(rt_sem_init);

脱离(内存继续存在,所以是脱离-内存还存在)
有初始化必有脱离

rt_err_t rt_sem_detach(rt_sem_t sem)
{
   
    /* parameter check */
    RT_ASSERT(sem != RT_NULL);//信号量对象的句柄是否存在
    RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore);//rt_object名字是否为信号量并返回对象类型
    RT_ASSERT(rt_object_is_systemobject(&sem->parent.parent));
    //判断对象是否为系统对象

    /* wakeup all suspend threads */
    rt_ipc_list_resume_all(&(sem->parent.suspend_thread));
    //唤醒挂起线程(为使用信号量排队的线程),让他们返回失败(别等了,停车场关门了)

    /* detach semaphore object */
    rt_object_detach(&(sem->parent.parent));//信号量对象从内核对象管理器中脱离

    return RT_EOK;
}
RTM_EXPORT(rt_sem_detach);

3.创建和删除

创建
和初始化差别:没有已存在的信号量句柄,要自己创建,要自己给内存

rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag)
{
   
    rt_sem_t sem;//定义信号量句柄

    RT_DEBUG_NOT_IN
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值