信號量是線程間同步的一種方式。在rtthread中用于線程間同步的還有互斥量和事件集。
什么是進(jìn)程間同步,簡單點(diǎn)的類比就是工廠中的生產(chǎn)線,如果想要執(zhí)行B工序就必須等待A工序的完成,那么工序A和工序B就是同步的關(guān)系,在程序中也是一樣。只不過是工序變成了線程。在RTThread的文檔里有這樣的描述:同步是指按預(yù)定的先后次序進(jìn)行運(yùn)行,線程同步是指多個線程通過特定的機(jī)制(如互斥量,事件對象,臨界區(qū))來控制線程之間的執(zhí)行順序,也可以說是在線程之間通過同步建立起執(zhí)行順序的關(guān)系,如果沒有同步,那線程之間將是無序的。
然后就是解釋一下信號量,一個經(jīng)典的解釋
以生活中的停車場為例來理解信號量的概念:
①當(dāng)停車場空的時候,停車場的管理員發(fā)現(xiàn)有很多空車位,此時會讓外面的車陸續(xù)進(jìn)入停車場獲得停車位;
②當(dāng)停車場的車位滿的時候,管理員發(fā)現(xiàn)已經(jīng)沒有空車位,將禁止外面的車進(jìn)入停車場,車輛在外排隊(duì)等候;
③當(dāng)停車場內(nèi)有車離開時,管理員發(fā)現(xiàn)有空的車位讓出,允許外面的車進(jìn)入停車場;待空車位填滿后,又禁止外部車輛進(jìn)入。
在此例子中,管理員就相當(dāng)于信號量,管理員手中空車位的個數(shù)就是信號量的值(非負(fù)數(shù),動態(tài)變化);停車位相當(dāng)于公共資源(臨界區(qū)),車輛相當(dāng)于線程。車輛通過獲得管理員的允許取得停車位,就類似于線程通過獲得信號量訪問公共資源。
最后信號量的使用。其實(shí)如果不追究內(nèi)核的話,操作系統(tǒng)只需要調(diào)用api就可以了。具體就是創(chuàng)建信號量(rt_sem_create)、刪除信號量(rt_sem_delete)獲取信號量( rt_sem_take)、釋放信號量( rt_sem_release)詳細(xì)使用手冊可以參考這里
接下來就是一個實(shí)驗(yàn),使用信號量控制LED以500ms的間隔閃爍。
思路:使用一個定時器:每500毫秒釋放一次信號量,在創(chuàng)建一個線程用來反轉(zhuǎn)LED燈,當(dāng)有信號量的時候就執(zhí)行反轉(zhuǎn)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); //線程初始化函數(shù)
static void led_entry(void *parameter);//LED反轉(zhuǎn)線程
static void timer(void *parameter);//定時器任務(wù)
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)
{
/* 創(chuàng)建一個動態(tài)信號量,初始值是 0,先進(jìn)先出*/
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 ;
}
//靜態(tài)創(chuàng)建任務(wù)
rt_thread_init(&led_thread, //線程句柄
"led on", //線程的描述
led_entry, //線程入口函數(shù)
RT_NULL, //線程入口參數(shù)
&led_stack[0],//線程的棧的起始地址
sizeof(led_stack),//線程的棧大小
3, 10);//線程的優(yōu)先級和時間片大小
rt_thread_startup(&led_thread);//啟動線程
timer_res = rt_timer_create("led sem",//定時器描述
timer,//定時器入口函數(shù)
RT_NULL,//定時器入口參數(shù)
500,//定時時間
RT_TIMER_FLAG_PERIODIC);//循環(huán)
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)
{
/*以永遠(yuǎn)阻塞的形式等待信號量*/
if(rt_sem_take (led_sem, RT_WAITING_FOREVER) == RT_EOK)
{
HAL_GPIO_TogglePin(GPIOH, GPIO_PIN_11);//反轉(zhuǎn)LED
rt_kprintf("led toggle.tick:%d n",rt_tick_get());
}
}
}
下面就是運(yùn)行結(jié)果
-
led燈
+關(guān)注
關(guān)注
22文章
1596瀏覽量
109716 -
定時器
+關(guān)注
關(guān)注
23文章
3298瀏覽量
118813 -
GPIO
+關(guān)注
關(guān)注
16文章
1280瀏覽量
54034 -
信號量
+關(guān)注
關(guān)注
0文章
53瀏覽量
8565 -
RTThread
+關(guān)注
關(guān)注
8文章
132瀏覽量
41748
發(fā)布評論請先 登錄
RTThread之操作系統(tǒng)移植
EN55032(2012)AC(2013)英文完整版
C語言程序設(shè)計上機(jī)考試練習(xí)題和答案免費(fèi)下載
SD卡協(xié)議學(xué)習(xí)點(diǎn)滴(完整版本)

評論