關鍵詞:sched_yield()、nanosleep()等等。ios
sched_yield()主動放棄CPU執行權,nanosleep()是睡眠一段時間後再喚醒。 cookie
sched_yield()會主動放棄當前CPU給其餘進程使用;可是若是當前CPU上無其餘進程等待執行,則直接返回繼續執行當前進程。性能
調用sched_yield()以後當前進程會被移動到進程優先級等待隊列尾部,讓相同或者更高優先級進程運行。this
sched_yield()確保當前進程在資源競爭嚴重時,給其餘進程執行機會來提升性能。atom
SYSCALL_DEFINE0(sched_yield) { struct rq *rq = this_rq_lock(); schedstat_inc(rq->yld_count); current->sched_class->yield_task(rq); __release(rq->lock); spin_release(&rq->lock.dep_map, 1, _THIS_IP_); do_raw_spin_unlock(&rq->lock); sched_preempt_enable_no_resched(); schedule(); return 0; } asmlinkage __visible void __sched schedule(void) { struct task_struct *tsk = current; sched_submit_work(tsk); do { preempt_disable(); __schedule(false); sched_preempt_enable_no_resched(); } while (need_resched()); } static void __sched notrace __schedule(bool preempt) { struct task_struct *prev, *next; unsigned long *switch_count; struct pin_cookie cookie; struct rq *rq; int cpu; ... next = pick_next_task(rq, prev, cookie);---------------------選擇優先級最高的進程做爲下一個運行進程。 clear_tsk_need_resched(prev); clear_preempt_need_resched(); rq->clock_skip_update = 0; if (likely(prev != next)) {----------------------------------若是sched_yield()後,當前進程prev即爲優先級最高的進程,即prev==next。那麼則不會進行進程切換操做,直接返回。 rq->nr_switches++; rq->curr = next; ++*switch_count; trace_sched_switch(preempt, prev, next); rq = context_switch(rq, prev, next, cookie); /* unlocks the rq */ } else { lockdep_unpin_lock(&rq->lock, cookie); raw_spin_unlock_irq(&rq->lock); } balance_callback(rq); }
對於CFS調度器類,yield_task()對應yield_task_fair()。spa
static void yield_task_fair(struct rq *rq) { struct task_struct *curr = rq->curr; struct cfs_rq *cfs_rq = task_cfs_rq(curr); struct sched_entity *se = &curr->se; if (unlikely(rq->nr_running == 1))--------------------若是當前運行隊列上僅有一個運行進程,直接返回。 return; clear_buddies(cfs_rq, se); if (curr->policy != SCHED_BATCH) { update_rq_clock(rq); update_curr(cfs_rq); rq_clock_skip_update(rq, true); } set_skip_buddy(se); }
下面是系統無其餘進程運行時,能夠看出進程獨佔了CPU很長時間。只是在有其餘內核線程運行後,才放棄CPU執行權。線程
#include <iostream> #include <chrono> #include <thread> #include <atomic> #include <mutex> #include <time.h> std::mutex g_mutex; std::atomic<bool> ready(false); void count1m(int id) { while (true) { } } int main() { std::thread threads; threads = std::thread(count1m, 1); threads.join(); return 0; }
這種狀況進程會盡量獨佔整個CPU,可是在有競爭進程存在的時候,須要和其餘進程均分CPU時間。因此出現下面每工做4ms,而後切換出去4ms時間的狀況。3d
在沒有其餘進程運行的時候,能夠獨佔CPU時間。code
#include <iostream> #include <chrono> #include <thread> #include <atomic> #include <mutex> #include <time.h> std::mutex g_mutex; std::atomic<bool> ready(false); void count1m(int id) { struct timespec delay; delay.tv_sec = 0; delay.tv_nsec = 1000000; while (true) { nanosleep(&delay, NULL); } } int main() { std::thread threads; threads = std::thread(count1m, 1); threads.join(); return 0; }
間隔休眠喚醒狀況下,即便系統中存在其餘進程在運行,當前進程喚醒後仍然能夠搶到CPU資源,sched_switch表示放入隊列,sched_wakeup表示獲得CPU資源,中間可能存在必定延時。blog
在沒有其餘進程狀況下,能更快獲得調度。
#include <iostream> #include <chrono> #include <thread> #include <atomic> #include <mutex> #include <time.h> std::mutex g_mutex; std::atomic<bool> ready(false); void count1m(int id) { while (true) { std::this_thread::yield(); } } int main() { std::thread threads; threads = std::thread(count1m, 1); threads.join(); return 0; }
這種狀況和第一種區別在於,sched_yield()會主動放棄CPU執行權。第一種狀況是根據CFS調度器類來分配時間;這裏還結合了進程主動放棄調度的狀況。
#include <iostream> #include <chrono> #include <thread> #include <atomic> #include <mutex> #include <time.h> std::mutex g_mutex; std::atomic<bool> ready(false); void count1m(int id) { struct timespec delay; delay.tv_sec = 0; delay.tv_nsec = 1000000; while (true) { std::this_thread::yield(); nanosleep(&delay, NULL); } } int main() { std::thread threads; threads = std::thread(count1m, 1); threads.join(); return 0; }
這種狀況下sched_yield()和nanosleep()疊加使用和單獨使用nanosleep()效果相似,nanosleep()本省也是主動放棄CPU使用權。
因此綜合來看while(1)中使用sched_yield()要比延時的響應更及時,可是也犧牲了CPU佔用率。在沒有其餘進程運行的狀況下,sched_yield()就會一我的獨佔CPU資源。