信號量是線程間同步的一種方式。在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());
}
}
}
下面就是運行結果
-
led燈
+關注
關注
22文章
1593瀏覽量
109307 -
定時器
+關注
關注
23文章
3284瀏覽量
117072 -
GPIO
+關注
關注
16文章
1261瀏覽量
53490 -
信號量
+關注
關注
0文章
53瀏覽量
8497 -
RTThread
+關注
關注
8文章
132瀏覽量
41510
發布評論請先 登錄
評論