RT-Thread——线程间同步之信号量

信号量

信号量可以看作是用于管理临界资源的管理员,信号量会统计临界资源的数量,从而控制线程的访问,如果信号量数量为0,则禁止线程访问,如果大于0,则允许线程访问

1.信号量工作机制

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

每个信号量对象都有一个信号量值和一个线程等待队列,信号量值用于统计资源数目,当信号量值为0时,申请信号量的线程就会被挂起在该信号量的等待队列上,等待可用的信号量实例

信号量的值最大为65535

信号量对象从rt_ipc_object中派生,由ipc容器管理

信号量对象代码:

struct rt_semaphore
{
   struct rt_ipc_object parent;  /* 继承自 ipc_object 类 */
   rt_uint16_t value;            /* 信号量的值 */
};
/* rt_sem_t 是指向 semaphore 结构体的指针类型 */
typedef struct rt_semaphore* rt_sem_t;

 2.信号量管理方式

  • 对一个信号量的操作包含:创建 / 初始化信号量、获取信号量、释放信号量、删除 / 脱离信号量。

  • 创建动态信号量

     rt_sem_t rt_sem_create(const char *name,
                            rt_uint32_t value,
                            rt_uint8_t flag);

         参数:name 信号量名称        value信号量初始值        

                    flag可以赋值为RT_IPC_FLAG_FIFO或者RT_IPC_FLAG_PRIO

                    选择RT_IPC_FLAG_FIFO(先进先出)方式时线程等待队列将按照先进先出的                              方式进行等待,即先到来的线程先获得资源
                    选择RT_IPC_FLAG_PRIO(优先级等待)方式时,等待队列将按照优先级高低对                          线程进行排队,优先级高的先获得资源

  • 删除动态信号量:
    rt_err_t rt_sem_delete(rt_sem_t sem);
    调用该函数删除信号量时,如果有线程在等待该信号量,那么删除操作会先唤醒等待在该信号量上的线程,然后再释放信号量的内存资源
    • 创建和删除静态信号量
      对于静态信号量对象,它的内存空间在编译时期就被编译器分配出来,放在读写数据段或未初始化数据段上,此时使用信号量就不再需要使用 rt_sem_create 接口来创建它,而只需在使用前对它进行初始化即可。
      rt_err_t rt_sem_init(rt_sem_t       sem,
                          const char     *name,
                          rt_uint32_t    value,
                          rt_uint8_t     flag)
      参数解释:sem信号量对象句柄        name信号量名称        value信号量初始值
                        flag信号量标志,与动态相同
  • 线程获取信号量
    • 线程通过获取信号量来获得信号量资源实例,当信号量值大于零时,线程将获得信号量,并且相应的信号量值会减 1,获取信号量使用下面的函数接口:
      rt_err_t rt_sem_take (rt_sem_t sem, rt_int32_t time);
      sem为线程需要获取的信号量句柄,time为线程获得信号量的等待时间,如果再time内获取不到信号量,线程将超时返回
    • 线程无等待获取信号量
      当用户不想在申请的信号量上挂起线程进行等待时,可以使用无等待方式获取信号量,无等待获取信号量使用下面的函数接口:
      rt_err_t rt_sem_trytake(rt_sem_t sem);
      调用该函数获取信号量时,若是当前申请的信号量资源实例不可用时,函数将直接返回    - RT_ETIMEOUT。
    • 释放信号量
      释放信号量可以唤醒挂起在该信号量上的线程。释放信号量使用下面的函数接口:
      rt_err_t rt_sem_release(rt_sem_t sem);
       该函数说是释放不如理解为赋予,调用该函数后信号量的值就会增加

 3.代码示例

代码创建了一个信号量,信号量值初始为0,两个线程,线程1先释放10个信号量值,当线程1释放10信号量值后,线程2再获取信号量10次

 

/*
 * Copyright (c) 2006-2024, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-08-28     RT-Thread    first version
 */

#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#define THREAD_PRIORITY         25
#define THREAD_TIMESLICE        5
int count=0;


/* 指向信号量的指针 */
static rt_sem_t dynamic_sem = RT_NULL;
static char thread1_stack[1024];
static struct rt_thread thread1;
static void rt_thread1_entry(void *parameter)
{


    while(1)
    {
        if(count < 100)
        {
            count++;
        }
        else
            return;

        /* count 每计数 10 次,就释放一次信号量 */
         if(0 == (count % 10))
        {

            rt_sem_release(dynamic_sem);
            rt_kprintf("t1 release a dynamic semaphore.\n");
            rt_kprintf("signal value %d\n",dynamic_sem->value);
        }
         rt_thread_mdelay(50);
    }
}



static char thread2_stack[1024];
static struct rt_thread thread2;
static void rt_thread2_entry(void *parameter)
{
    static rt_err_t result;
    static rt_uint8_t number = 0;
    while(1)
    {
        /* 永久方式等待信号量,获取到信号量,则执行 number 自加的操作 */
        if(count==100)
        {
        result = rt_sem_take(dynamic_sem, RT_WAITING_FOREVER);

          if(result==RT_EOK)
          {
              number++;
              rt_kprintf("t2 take a dynamic semaphore. number = %d\n" ,number);
          }


        }

        rt_thread_mdelay(100);
    }
}



int main(void)
{
    /* 创建一个动态信号量,初始值是 0 */
       dynamic_sem = rt_sem_create("dsem", 0, RT_IPC_FLAG_PRIO);
       if (dynamic_sem == RT_NULL)
          {
              rt_kprintf("create dynamic semaphore failed.\n");
              return -1;
          }
          else
          {
              rt_kprintf("create done. dynamic semaphore value = 0.\n");
          }

       rt_thread_init(&thread1,
                         "thread1",
                         rt_thread1_entry,
                         RT_NULL,
                         &thread1_stack[0],
                         sizeof(thread1_stack),
                         THREAD_PRIORITY, THREAD_TIMESLICE);
          rt_thread_startup(&thread1);

          rt_thread_init(&thread2,
                         "thread2",
                         rt_thread2_entry,
                         RT_NULL,
                         &thread2_stack[0],
                         sizeof(thread2_stack),
                         THREAD_PRIORITY-1, THREAD_TIMESLICE);
          rt_thread_startup(&thread2);

    return RT_EOK;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值