TThread完整版学习(RCEA考试练习)之信号量使用

描述

信号量是线程间同步的一种方式。在rtthread中用于线程间同步的还有互斥量和事件集。

什么是进程间同步,简单点的类比就是工厂中的生产线,如果想要执行B工序就必须等待A工序的完成,那么工序A和工序B就是同步的关系,在程序中也是一样。只不过是工序变成了线程。在RTThread的文档里有这样的描述:同步是指按预定的先后次序进行运行,线程同步是指多个线程通过特定的机制(如互斥量,事件对象,临界区)来控制线程之间的执行顺序,也可以说是在线程之间通过同步建立起执行顺序的关系,如果没有同步,那线程之间将是无序的。

然后就是解释一下信号量,一个经典的解释

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

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

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

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

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

最后信号量的使用。其实如果不追究内核的话,操作系统只需要调用api就可以了。具体就是创建信号量(rt_sem_create)、删除信号量(rt_sem_delete)获取信号量( rt_sem_take)、释放信号量( rt_sem_release)详细使用手册可以参考这里

接下来就是一个实验,使用信号量控制LED以500ms的间隔闪烁。

思路:使用一个定时器:每500毫秒释放一次信号量,在创建一个线程用来反转LED灯,当有信号量的时候就执行反转LED灯。

程序部分

/* defined the LED0 pin: PB1 */
#define LED0_PIN    GET_PIN(H, 11)


//定义信号量
static rt_sem_t led_sem = RT_NULL; 
//定义线程
static char led_stack[512];
static struct rt_thread led_thread;
//定时器定义
static rt_timer_t timer_res;

void task_init(void); //线程初始化函数
static void led_entry(void *parameter);//LED反转线程
static void timer(void *parameter);//定时器任务


int main(void)
{
    /* set LED0 pin mode to output */
    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
  task_init();
    while (1)
    {
        rt_thread_mdelay(1000);
    }


}


void task_init(void)
{


  /* 创建一个动态信号量,初始值是 0,先进先出*/
    led_sem = rt_sem_create("led on sem", 0, RT_IPC_FLAG_FIFO);
    if (led_sem == RT_NULL)
    {
        rt_kprintf("create led on semaphore failed.n");
        return ;
    }
  //静态创建任务
  rt_thread_init(&led_thread, //线程句柄 
                   "led on", //线程的描述
                   led_entry, //线程入口函数
                   RT_NULL, //线程入口参数
                   &led_stack[0],//线程的栈的起始地址
                   sizeof(led_stack),//线程的栈大小
                   3, 10);//线程的优先级和时间片大小
    rt_thread_startup(&led_thread);//启动线程

  timer_res = rt_timer_create("led sem",//定时器描述
                     timer,//定时器入口函数
                     RT_NULL,//定时器入口参数
                     500,//定时时间
                     RT_TIMER_FLAG_PERIODIC);//循环  
  if(timer_res != RT_NULL)
  {
    rt_timer_start(timer_res);//定时器开始
    rt_kprintf("timer start. n");
  }
}


static void timer(void *parameter)
{
  rt_sem_release(led_sem);//释放信号量
}




static void led_entry(void *parameter)
{
  while(1)
  {
    /*以永远阻塞的形式等待信号量*/
    if(rt_sem_take (led_sem, RT_WAITING_FOREVER) == RT_EOK)
    {
      HAL_GPIO_TogglePin(GPIOH, GPIO_PIN_11);//反转LED
      rt_kprintf("led toggle.tick:%d n",rt_tick_get());
    }
  }
}

下面就是运行结果

GPIO

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
评论(0)
发评论
jf_88411403 2023-07-27
0 回复 举报
学习了,测试! 收起回复

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分