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


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

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

1. sched_yield()實現

sched_yield()會主動放棄當前CPU給其他進程使用;但是如果當前CPU上無其他進程等待執行,則直接返回繼續執行當前進程。

調用sched_yield()之后當前進程會被移動到進程優先級等待隊列尾部,讓相同或者更高優先級進程運行。

sched_yield()確保當前進程在資源競爭嚴重時,給其他進程執行機會來提高性能。

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()。

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時間的情況。

在沒有其他進程運行的時候,可以獨占CPU時間。

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資源,中間可能存在一定延時。

在沒有其他進程情況下,能更快得到調度。

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM