sched_yield()和nanosleep()對進程調度的影響

關鍵詞:sched_yield()、nanosleep()等等。ios

sched_yield()主動放棄CPU執行權,nanosleep()是睡眠一段時間後再喚醒。 cookie

1. sched_yield()實現

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執行權。線程

2. nanosleep()和sched_yield()對比

2.1 while(true)儘可能獨佔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

2.2 nanosleep()進程休眠一段時間

#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

在沒有其餘進程狀況下,能更快獲得調度。

2.3 sched_yield()主動放棄

#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調度器類來分配時間;這裏還結合了進程主動放棄調度的狀況。

2.4 sched_yield()和nanosleep()混合使用

#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資源。

相關文章
相關標籤/搜索