日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux 下的推迟执行

發布時間:2023/12/20 linux 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux 下的推迟执行 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

準備中秋節

說個活動,評論文章點贊排名,用心評論哦,前5名獲得每人 19 心意紅包。

感謝大家的支持

我最近在用freertos,想讓一個任務在某個時間后再執行,找了一圈,竟然沒有這樣才處理機制,因為也是新手入門freertos,可能需要自己實現,當然了,自己實現的話,機制就很多了,但是有個問題是,自己實現的話,就感覺不夠規范,因為這樣的原因,我還特意從Linux上移植了time_before和time_after過去,用了下,感覺還是很爽的。

Linux 有延遲執行的機制,有幾種辦法

1、忙等待

聽到這個就知道了,如果是忙等待的話,肯定是占用cpu的,所以忙等待其實也是使用了time_before這個宏來實現。

#define time_after(a,b) \ (typecheck(unsigned long, a) && \ typecheck(unsigned long, b) && \ ((long)((b) - (long)(a)) < 0)) time_before(a,b) time_after(b,a)

這個是實現的原型,time_before也就是time_after反過來而已,我們之前有一篇文章討論了time_after宏的實現和用法。不清楚的同學可以去看看,其中把無符號強制轉成有符號是關鍵。

那我們怎么使用這個忙等待呢

很簡單

unsigned long timeout = jiffies +10; while(time_before(jiffies,timeout));

while 循環會一直執行,因為time_before會一直返回true,知道jiffies的時間超過timeout的時間,這時候就會返回false。

也可以是這樣使用

unsigned long timeout = jiffies +2*HZ; while(time_before(jiffies,timeout));

這個是等待2秒,一秒鐘的節拍數是HZ,所以2秒就是2*HZ,這個好像太簡單了些。

2、短延遲

這個也類似于忙等待,但是這個忙等待使用的函數不同,我們使用jiffies使用的是系統軟件滴答數來做延遲,精度和時間上都有一定的局限性,但是使用delay函數的話,會相對好一些,時間的精準度會比較好。

void udelay(unsigned long usecs) void ndelay(unsigned long usecs) void mdelay(unsigned long usecs)

學習單片機的同學都知道,CPU執行的時間可以通過指令周期來確定時間,指令周期就是執行一條簡單的指令所花費的時間,80C51下我知道是多少,ARM我還不懂,但是這些我們也不用太關心,每個體系結構下的delay實現,他們都自己計算實現好了,這也是使用系統和單片機的好處,封裝什么的都搞好,就是要會使用才是關鍵。

用延遲實現的弊端就是會一直占用CPU時間,系統調用需要非常良好的性能,所以我們使用上面delay函數的時候,如果大于1ms的話,就可以換一種實現方式了。

1、時鐘周期 = 振蕩周期,名稱不同而已,都是等于單片機晶振頻率的倒數,如常見的外接12M晶振,那它的時鐘周期=1/12M。

2、機器周期,8051系列單片機的機器周期=12*時鐘周期,之所以這樣分是因為單個時鐘周期根本干不了一件完整的事情(如取指令、寫寄存器、讀寄存器等),而12個時鐘周期就能基本完成一項基本操作了。

3、指令周期。一個機器周期能完成一項基本操作,但一條指令常常是需要多項基本操作結合才能完成,完成一條指令所需的時間就是指令周期,當然不同的指令,其指令周期就不一樣的了。

3、schedule_timeout

在上面兩種方法的局限下,這個應該是最好的實現方式了,它的好是因為他可以睡眠,睡眠有一個好處就是不需要占用CPU資源,等時間到了再起床去干活就好了。

set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(S*HZ);

上面的代碼是讓當前任務進入不可中斷狀態,任何睡眠S秒后再起床,使用schedule_timeout的時候,一定要記得設置狀態,不然不能睡覺就麻煩了,也要注意你自己寫的代碼能不能睡眠,要不然引起問題就更尷尬了。

fastcall signed long __sched schedule_timeout(signed long timeout) { struct timer_list timer; unsigned long expire; switch (timeout) { case MAX_SCHEDULE_TIMEOUT: /* * These two special cases are useful to be comfortable * in the caller. Nothing more. We could take * MAX_SCHEDULE_TIMEOUT from one of the negative value * but I' d like to return a valid offset (>=0) to allow * the caller to do everything it want with the retval. */ schedule(); goto out; default: /* * Another bit of PARANOID. Note that the retval will be * 0 since no piece of kernel is supposed to do a check * for a negative retval of schedule_timeout() (since it * should never happens anyway). You just have the printk() * that will tell you if something is gone wrong and where. */ if (timeout < 0) { printk(KERN_ERR "schedule_timeout: wrong timeout " "value %lx from %p\n", timeout, __builtin_return_address(0)); current->state = TASK_RUNNING; goto out; } } expire = timeout + jiffies; init_timer(&timer); timer.expires = expire; timer.data = (unsigned long) current; timer.function = process_timeout; add_timer(&timer); schedule(); del_singleshot_timer_sync(&timer); timeout = expire - jiffies; out: return timeout < 0 ? 0 : timeout; }

網上有挺多文章說明了這個函數的實現,首先是初始化一個timer,然后往timer里去傳初始化參數,其中有一個參數是current,這個是一個宏,這個宏的作用是獲取當前的task,然后再設置超時時間,超時時間到了之后,通過調用process_timeout去喚醒之前休眠的task。

我們可以這樣使用,當做一個delay來嵌入自己的代碼中

inline static void snd_xx_delay_long(void) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1); }

掃碼或長按關注

總結

以上是生活随笔為你收集整理的Linux 下的推迟执行的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。