RT-Thread信号量的简单应用

信号量(Semaphore)是在多线程环境下使用的一种设施,可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。

下面通过RT-Thread的信号量来完成一个简单的应用:LED2和LED3以1Hz的频率交替闪烁。

信号量是进程间通信的媒介,在此定义两个线程thread1和thread2。Thread1首先获取一个信号量,然后点亮LED2,延迟500ms过后熄灭LED2,随即释放一个信号量。Thread2以RT_WAITING_FOREVER的方式一直保持获取信号量,当Thread1释放信号量之后,Thread2获取到一个信号量开始运行,点亮LED3,延迟500ms过后熄灭,随即释放一个信号量。

下面按照步骤完整地实现该例程:

1. 首先当然是定义两个LED灯啦!在jiezhi320讲解的《15天入门RT-Thread》视频第2课中,LED的定义方式使用了RT-Thread自带的API,我也用此方式初始化两个LED。我使用的STM32开发板以STM32F103ZET6为主控芯片,该芯片为144脚。通过查看电路原理图,得到LED2对应PE5,即芯片的第4脚;LED3对应芯片的PB5,即芯片的第135脚。如下图所示:

    

2.在rtconfig.h文件中,以具体的名称代替引脚序号:

#define LED_2_PIN 4    //LED2 connect to PE5-the forth pin of stm32f103zet6
#define LED_3_PIN 135  //LED3 connect to PB5-the 135th pin of stm32f103zet6

3.新建一个semaphore_led.c文件,例程的所有源码都将在此文件中编写。semaphore_led.c文件中加入两个头文件

#include <rtthread.h> //Some important API is defined in this head-file
#include <rtdevice.h> //Devices like PIN/I2C/SDIO can be configured in this head-file

4.将LED_2_PIN和LED_3_PIN设置为输出模式。这儿提一下,jiezhi320的《15天入门RT-Thread》第2课时此处配置有误,引脚的模式应该是OUTPUT而不是INPUT。

void semaphore_led_init(void)
{
	rt_pin_mode(LED_2_PIN,PIN_MODE_OUTPUT);
	rt_pin_mode(LED_3_PIN,PIN_MODE_OUTPUT);
}

5.编写thread1和thread2的入口函数。Thread1以RT_WAITING_FOREVER的方式获取一个信号量,操作完LED2后释放信号量。此时while循环应该继续运行的,但是由于thread1释放信号量之后,thread2以RT_WAITING_FOREVER的方式获取到了信号量,使信号量的value为0,thread1便停止在result = rt_sem_take(dynamic_sem,RT_WAITING_FOREVER)处。Thread2操作完LED3之后,释放了一个信号量,Thread1获取到该信号量,继续运行。

void rt_thread_entry1(void *parameter)
{
	rt_err_t result = RT_NULL;
	while(1)
	{	
		result = rt_sem_take(dynamic_sem,RT_WAITING_FOREVER);
		if(result != RT_EOK)
		{
			return;
		}
		rt_kprintf("thread1 take 1 sem\n");
		rt_pin_write(LED_2_PIN,0);
		rt_kprintf("led2-on in thread1 \n");
		rt_thread_delay(RT_TICK_PER_SECOND/2);//RT_TICK_PER_SECOND = 100;delay 500ms;
		rt_pin_write(LED_2_PIN,1);
		rt_kprintf("led2-off in thread1 \n");
		rt_kprintf("thread1 release 1 sem\n");//if we put the line of code behind the next line
                                                      //we won't see anything printed,guess why?
		rt_sem_release(dynamic_sem);
	}
}

void rt_thread_entry2(void *parameter)
{
	rt_err_t result = RT_NULL;
	while(1)
	{
		result = rt_sem_take(dynamic_sem,RT_WAITING_FOREVER);
		if(result != RT_EOK)
		{
			return;
		}
		rt_kprintf("thread2 take 1 sem\n");
		rt_pin_write(LED_3_PIN,0);
		rt_kprintf("led3-on in thread2 \n");
		rt_thread_delay(RT_TICK_PER_SECOND/2);
		rt_pin_write(LED_3_PIN,1);
		rt_kprintf("led3-off in thread2 \n");
		rt_kprintf("thread2 release 1 sem\n");
		rt_sem_release(dynamic_sem);
	}
}

6.创建并启动thread1和thread2,并将该例程加入到finsh命令行中;整个程序就完成了。

int semaphore_led_sample_init(void *parameter)
{
	semaphore_led_init();
	
	dynamic_sem = rt_sem_create("dsem",1,RT_IPC_FLAG_FIFO);
	if(dynamic_sem == RT_NULL)
	{
		rt_kprintf("Failed to create dynamic semaphore! \n");
		return 1;
	}
	
	tid1 = rt_thread_create("thread1",rt_thread_entry1,RT_NULL,512,5,10);
	if(tid1 == RT_NULL)
	{
		rt_kprintf("Failed to create thread1\n");
		return 1;
	}
	rt_thread_startup(tid1);
	
	tid2 = rt_thread_create("thread2",rt_thread_entry2,RT_NULL,512,6,10);
	if(tid2 == RT_NULL)
	{
		rt_kprintf("Failed to create thread2\n");
		return 1;
	}
	rt_thread_startup(tid2);
	return 0;
}

#if defined (RT_SAMPLES_AUTORUN) && defined(RT_USING_COMPONENTS_INIT)
    INIT_APP_EXPORT(semaphore_led_sample_init);
#endif

MSH_CMD_EXPORT(semaphore_led_sample_init, semaphore led sample);

下面给出整个semaphore_led.c文件,添加到《15天入门RT-Thread》工程文件中,编译过后烧录进硬件板中,就可以观察到LED2和LED3交替闪烁并且打印相关信息了。注意:请根据自己的开发板使用的STM32芯片调整LED2和LED3连接的引脚。48脚、64脚、100脚和144脚的引脚定义是不一样的。如有疑问可以查阅Drivers->drv_gpio.c文件。

#include <rtthread.h>
#include <rtdevice.h>

static rt_sem_t dynamic_sem = RT_NULL;

static rt_thread_t tid1,tid2;

void semaphore_led_init(void)
{
	rt_pin_mode(LED_2_PIN,PIN_MODE_OUTPUT);
	rt_pin_mode(LED_3_PIN,PIN_MODE_OUTPUT);
}

void rt_thread_entry1(void *parameter)
{
	rt_err_t result = RT_NULL;
	while(1)
	{	
		result = rt_sem_take(dynamic_sem,RT_WAITING_FOREVER);
		if(result != RT_EOK)
		{
			return;
		}
		rt_kprintf("thread1 take 1 sem\n");
		rt_pin_write(LED_2_PIN,0);
		rt_kprintf("led2-on in thread1 \n");
		rt_thread_delay(RT_TICK_PER_SECOND/2);//RT_TICK_PER_SECOND = 100;delay 500ms;
		rt_pin_write(LED_2_PIN,1);
		rt_kprintf("led2-off in thread1 \n");
		rt_kprintf("thread1 release 1 sem\n");
		rt_sem_release(dynamic_sem);
	}
}

void rt_thread_entry2(void *parameter)
{
	rt_err_t result = RT_NULL;
	while(1)
	{
		result = rt_sem_take(dynamic_sem,RT_WAITING_FOREVER);
		if(result != RT_EOK)
		{
			return;
		}
		rt_kprintf("thread2 take 1 sem\n");
		rt_pin_write(LED_3_PIN,0);
		rt_kprintf("led3-on in thread2 \n");
		rt_thread_delay(RT_TICK_PER_SECOND/2);
		rt_pin_write(LED_3_PIN,1);
		rt_kprintf("led3-off in thread2 \n");
		rt_kprintf("thread2 release 1 sem\n");
		rt_sem_release(dynamic_sem);
	}
}

int semaphore_led_sample_init(void *parameter)
{
	semaphore_led_init();
	
	dynamic_sem = rt_sem_create("dsem",1,RT_IPC_FLAG_FIFO);
	if(dynamic_sem == RT_NULL)
	{
		rt_kprintf("Failed to create dynamic semaphore! \n");
		return 1;
	}
	
	tid1 = rt_thread_create("thread1",rt_thread_entry1,RT_NULL,512,5,10);
	if(tid1 == RT_NULL)
	{
		rt_kprintf("Failed to create thread1\n");
		return 1;
	}
	rt_thread_startup(tid1);
	
	tid2 = rt_thread_create("thread2",rt_thread_entry2,RT_NULL,512,6,10);
	if(tid2 == RT_NULL)
	{
		rt_kprintf("Failed to create thread2\n");
		return 1;
	}
	rt_thread_startup(tid2);
	return 0;
}

#if defined (RT_SAMPLES_AUTORUN) && defined(RT_USING_COMPONENTS_INIT)
    INIT_APP_EXPORT(semaphore_led_sample_init);
#endif

MSH_CMD_EXPORT(semaphore_led_sample_init, semaphore led sample);

猜你喜欢

转载自blog.csdn.net/qq_36880027/article/details/81538722