日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

線程的基本概念和調(diào)度策略

 luokp 2012-04-25
分類(lèi): linux學(xué)習(xí)


關(guān)鍵詞:線程 進(jìn)程 優(yōu)先級(jí) 調(diào)度策略 時(shí)間片
一、線程的基本概念
進(jìn)程(process)和文件(files)是UNIX/Linux操作系統(tǒng)兩個(gè)最基本的抽象。進(jìn)程是處于執(zhí)行期的程序和它所包含的資源的總和,也就是說(shuō)一個(gè)進(jìn)程就是處于執(zhí)行期的程序。一個(gè)線程thread)就是運(yùn)行在一個(gè)進(jìn)程上下文中的一個(gè)邏輯流,不難看出,線程是進(jìn)程中最基本的活動(dòng)對(duì)象。
在傳統(tǒng)的系統(tǒng)中,一個(gè)進(jìn)程只包含一個(gè)線程。但在現(xiàn)代操作系統(tǒng)中,允許一個(gè)進(jìn)程里面可以同時(shí)運(yùn)行多個(gè)線程,這類(lèi)程序就被稱(chēng)為多線程程序。所有的程序都有一個(gè)主線程(main thread),主線程是進(jìn)程的控制流或執(zhí)行線程,見(jiàn)圖1。在多線程程序中,主線程可以創(chuàng)建一個(gè)或多個(gè)對(duì)等線程(peer thread),從這個(gè)時(shí)間點(diǎn)開(kāi)始,這些線程就開(kāi)始并發(fā)執(zhí)行,見(jiàn)圖2。主線程和對(duì)等線程的區(qū)別僅在于主線程總是進(jìn)程中第一個(gè)運(yùn)行的線程。從某種程度上看,線程可以看作是輕量級(jí)的進(jìn)程(lightweight process)。在Linux操作系統(tǒng)中,內(nèi)核調(diào)度的基本對(duì)象是線程,而不是進(jìn)程,所以進(jìn)程中的多個(gè)線程將由內(nèi)核自動(dòng)調(diào)度。
每個(gè)線程都擁有獨(dú)立的線程上下文(thread context),線程ID(Thread ID,TID),程序計(jì)數(shù)器(pc),線程棧(stack),一組寄存器(register)和條件碼。其中,內(nèi)核正是通過(guò)線程ID(TID)來(lái)識(shí)別線程,進(jìn)行線程調(diào)度的。
1多線程進(jìn)程的控制流
2并發(fā)線程執(zhí)行模型

線程和進(jìn)程在很多方面是相似的。相同點(diǎn)主要表現(xiàn)在如下幾方面:
1)        比如都具有ID,一組寄存器,狀態(tài),優(yōu)先級(jí)以及所要遵循的調(diào)度策略。
2)        每個(gè)進(jìn)程都有一個(gè)進(jìn)程控制塊,線程也擁有一個(gè)線程控制塊(在Linux內(nèi)核,線程控制塊與進(jìn)程控制塊用同一個(gè)結(jié)構(gòu)體描述,即struct task_struct),這個(gè)控制塊包含線程的一些屬性信息,操作系統(tǒng)使用這些屬性信息來(lái)描述線程。
3)        線程和子進(jìn)程共享父進(jìn)程中的資源。
4)        線程和子進(jìn)程獨(dú)立于它們的父進(jìn)程,競(jìng)爭(zhēng)使用處理器資源。
5)        線程和子進(jìn)程的創(chuàng)建者可以在線程和子進(jìn)程上實(shí)行某些控制,比如,創(chuàng)建者可以取消、掛起、繼續(xù)和修改線程和子進(jìn)程的優(yōu)先級(jí)。
6)        線程和子進(jìn)程可以改變其屬性并創(chuàng)建新的資源
除了這些相同點(diǎn),在很多方面也存在著差異:
1)        主要區(qū)別:每個(gè)進(jìn)程都擁有自己的地址空間,但線程沒(méi)有自己獨(dú)立的地址空間,而是運(yùn)行在一個(gè)進(jìn)程里的所有線程共享該進(jìn)程的整個(gè)虛擬地址空間
2)        線程的上下文切換時(shí)間開(kāi)銷(xiāo)比進(jìn)程上下文切換時(shí)間開(kāi)銷(xiāo)要小的多
3)        線程的創(chuàng)建開(kāi)銷(xiāo)遠(yuǎn)遠(yuǎn)小于進(jìn)程的創(chuàng)建
4)        子進(jìn)程擁有自己的地址空間和數(shù)據(jù)段的拷貝,因此當(dāng)子進(jìn)程修改它的變量和數(shù)據(jù)時(shí),它不會(huì)影響父進(jìn)程中的數(shù)據(jù),但線程可以直接訪問(wèn)它進(jìn)程中的數(shù)據(jù)段
5)        進(jìn)程之間通訊必須使用進(jìn)程間通訊機(jī)制,但線程可以與進(jìn)程中的其他線程直接通訊
6)        線程可以對(duì)同一進(jìn)程中的其他線程實(shí)施大量控制,但進(jìn)程只能對(duì)子進(jìn)程實(shí)施控制
7)        改變主線程的屬性可能影響進(jìn)程中其他的線程,但對(duì)父進(jìn)程的修改不影響子進(jìn)程。
  二、進(jìn)程和線程的優(yōu)先級(jí)
進(jìn)程優(yōu)先級(jí)只是線程優(yōu)先級(jí)的前身。當(dāng)調(diào)用 fork() 子例程時(shí),會(huì)創(chuàng)建一個(gè)進(jìn)程和一個(gè)要在其中運(yùn)行的線程。線程的優(yōu)先級(jí)歸結(jié)于進(jìn)程。

內(nèi)核為每個(gè)線程維護(hù)一個(gè)優(yōu)先級(jí)值(有時(shí)稱(chēng)為調(diào)度優(yōu)先級(jí))。優(yōu)先級(jí)值是一個(gè)正整數(shù)且與關(guān)聯(lián)線程的重要性的變化方向相反。也就是說(shuō),較小的優(yōu)先級(jí)值表示一個(gè)相對(duì)重要的線程。當(dāng)調(diào)度程序?qū)ふ揖€程進(jìn)行分派時(shí),它選擇具有較小優(yōu)先級(jí)值的可分派線程。

線程可以有固定的優(yōu)先級(jí)或不固定的優(yōu)先級(jí)。優(yōu)先級(jí)固定的線程的優(yōu)先級(jí)值是一個(gè)常量,而優(yōu)先級(jí)不固定的線程的優(yōu)先級(jí)值根據(jù)用戶(hù)線程最小優(yōu)先級(jí)級(jí)別(常量 40)、線程的 nice 值(缺省值是 20,可隨意由 nicerenice 命令進(jìn)行設(shè)置)和其處理器使用的損失而變化。

線程的優(yōu)先級(jí)可以固定成某個(gè)值,如果用 setpri() 子例程設(shè)置(固定)它們的優(yōu)先級(jí)的話(huà),它們可以具有小于 40 的優(yōu)先級(jí)值。這些線程不會(huì)受到調(diào)度程序重算算法的影響。如果它們的優(yōu)先級(jí)值固定且小于 40,這些線程將在可以運(yùn)行所有用戶(hù)線程之前運(yùn)行和完成。例如,一個(gè)具有固定值 10 的線程將在具有固定值 15 的線程之前運(yùn)行。

用戶(hù)可以應(yīng)用 nice 命令使線程的不固定優(yōu)先級(jí)變低。系統(tǒng)管理員可將一個(gè)負(fù)的 nice 值應(yīng)用給線程,這樣就給了它較好的優(yōu)先級(jí)。

下圖顯示了一些可以更改優(yōu)先級(jí)值的方法。

圖 1. 如何確定優(yōu)先級(jí)值. 插圖顯示了如何能在執(zhí)行過(guò)程中或應(yīng)用了 nice 命令之后更改線程調(diào)度優(yōu)先級(jí)值。優(yōu)先級(jí)值越小,線程優(yōu)先級(jí)越高。開(kāi)始時(shí),nice 值缺省為 20 而基本優(yōu)先級(jí)缺省為 40。執(zhí)行中發(fā)生了處理器損失后,nice 的值仍然保持 20,基本優(yōu)先級(jí)仍然保持 40。在運(yùn)行 renice —5 命令后及使用和以前相同的處理器(CPU)的情況下,nice 值現(xiàn)在是 15 而基本優(yōu)先級(jí)仍然是 40。在以 50 的值發(fā)出子例程 setpri() 之后,固定優(yōu)先級(jí)現(xiàn)在是 50 而 nice 值和處理器(CPU)的使用不相關(guān)。h02i1 圖形

線程的 nice 值在創(chuàng)建線程時(shí)設(shè)置并且在線程的整個(gè)生命期中都是常量,除非用戶(hù)通過(guò) renice 命令或 setpri()、setpriority()thread_setsched()nice() 系統(tǒng)調(diào)用明確更改了它的值。

處理器損失是一個(gè)整數(shù),它通過(guò)線程最近的處理器使用來(lái)計(jì)算。如果每次在一個(gè) 10 ms 的時(shí)鐘滴答結(jié)束時(shí)線程受處理器控制,則最近的處理器使用值近似加 1,直到達(dá)到最大值 120。每個(gè)滴答的實(shí)際優(yōu)先級(jí)損失隨著 nice 的值增加。所有線程的最近處理器使用值每秒重算一次。

結(jié)果如下:

  •        不固定優(yōu)先級(jí)的線程的優(yōu)先級(jí)隨著其最近處理器使用的增加而變低,反之亦然。這暗示一般來(lái)講,某線程最近被分配的時(shí)間片越多,則它被分配下一個(gè)時(shí)間片的可能性越小。
  •        不固定優(yōu)先級(jí)的線程的優(yōu)先級(jí)隨著其 nice 值的增加而變低,反之亦然。
注: 使用多處理器運(yùn)行隊(duì)列及其負(fù)載平衡機(jī)制以后,nicerenice 的值對(duì)線程的優(yōu)先級(jí)可能沒(méi)有預(yù)期的影響,因?yàn)檩^低優(yōu)先級(jí)的運(yùn)行時(shí)間可能等于或大于較高優(yōu)先級(jí)的運(yùn)行時(shí)間。要求 nicerenice 產(chǎn)生預(yù)期效果的線程應(yīng)該放在全局運(yùn)行隊(duì)列中。
  三、線程調(diào)度策略
Pthread 調(diào)度
POSIX 定義一種優(yōu)先級(jí)調(diào)度模型,此模型確定任何兩個(gè)線程相對(duì)于對(duì)方的重要程度。 每當(dāng)有一個(gè)以上的線程可以運(yùn)行—執(zhí)行就緒—時(shí),系統(tǒng)都將選擇具有最高優(yōu)先級(jí)的線程。

POSIX 線程調(diào)度語(yǔ)義是按照一種概念模型定義的,在此概念模型中有一個(gè)有效優(yōu)先級(jí)范圍,并且有一組線程列表,每個(gè)優(yōu)先級(jí)分配有一個(gè)列表。根據(jù)線程的調(diào)度優(yōu)先級(jí),將任何可運(yùn)行的線程放置在其中一個(gè)線程列表上。線程列表內(nèi)的排序取決于調(diào)度策略。因此,每個(gè)線程都受其調(diào)度優(yōu)先級(jí)及其調(diào)度策略控制。

調(diào)度策略的作用是定義這些線程列表上的操作,如在列表內(nèi)和列表之間移動(dòng)線程。 不管策略如何,POSIX 都指定具有最高優(yōu)先級(jí)的線程列表中的第一個(gè)線程應(yīng)為當(dāng)前運(yùn)行的線程。

調(diào)度線程優(yōu)先級(jí)的能力是 POSIX 標(biāo)準(zhǔn)中的一個(gè)選項(xiàng),由符號(hào) POSIX_THREAD_PRIORITY_SCHEDULING 指定。支持此選項(xiàng)的 POSIX 實(shí)現(xiàn)還必須提供給線程指定實(shí)時(shí)調(diào)度策略和優(yōu)先級(jí)的機(jī)制。 強(qiáng)制性策略為 SCHED_FIFO、SCHED_RR 和 SCHED_OTHER。

SCHED_FIFO(先進(jìn)先出)策略按線程在執(zhí)行前在列表上存在的時(shí)間對(duì)列表上的線程進(jìn)行排序。處于列表首位的線程通常為在列表上存在時(shí)間最長(zhǎng)的線程,而處于末尾的線程在列表上存在的時(shí)間最短。此策略允許一個(gè)線程一直運(yùn)行,直到具有較高優(yōu)先級(jí)的另一個(gè)線程已準(zhǔn)備好運(yùn)行,或者直到當(dāng)前線程自動(dòng)阻止。如果此線程被占據(jù),它就繼續(xù)處于其線程優(yōu)先級(jí)列表的首位;如果此線程阻止,當(dāng)它再次成為一個(gè)可運(yùn)行的線程時(shí),將被添加到此線程所在的優(yōu)先級(jí)列表的末尾。

SCHED_RR (循環(huán)法)策略與 SCHED_FIFO 策略相同,不同的只是運(yùn)行的線程在被占據(jù)之前只能運(yùn)行有限的時(shí)間長(zhǎng)度。當(dāng)超過(guò)此固定時(shí)限時(shí),運(yùn)行的線程就被放到線程優(yōu)先級(jí)列表的末尾,而現(xiàn)在處于列表首位的線程將成為運(yùn)行的線程。 此策略的作用是確保具有相同優(yōu)先級(jí)的多個(gè) SCHED_RR 線程能共享處理器。

SCHED_OTHER 策略是針對(duì)具體實(shí)現(xiàn)的,相容的 POSIX 實(shí)現(xiàn)必須記錄此策略的行為。 一個(gè)實(shí)施可將此策略定義為與 SCHED_FIFO 或 SCHED_RR 相同,也可以定義為與這兩種策略完全不同的策略。 POSIX 定義此類(lèi)策略的目的是為相容的程序提供一種方法來(lái)表明這些程序不需要可移植的實(shí)時(shí)調(diào)度策略。

每種調(diào)度策略都有一個(gè)優(yōu)先級(jí)的有效范圍;對(duì)于 SCHED_FIFO 和 SCHED_RR,此范圍必須至少是 32,而對(duì)于 SCHED_OTHER,此范圍是針對(duì)具體實(shí)現(xiàn)的。 可以從 sched_get_priority_min() 函數(shù)和 sched_get_priority_max() 函數(shù)確定優(yōu)先級(jí)的范圍。

PThread 調(diào)度爭(zhēng)用范圍和分配域
除線程調(diào)度策略和線程優(yōu)先級(jí)外,還有其他兩種調(diào)度控制: 線程調(diào)度爭(zhēng)用范圍和線程調(diào)度分配域。

爭(zhēng)用范圍定義競(jìng)爭(zhēng)使用處理資源的線程集。 POSIX 定義兩個(gè)爭(zhēng)用范圍:系統(tǒng)中的所有線程(或 PTHREAD_SCOPE_SYSTEM)以及一個(gè)進(jìn)程中的所有線程(或 PTHREAD_SCOPE_PROCESS)。

系統(tǒng)爭(zhēng)用范圍中的一個(gè)線程與系統(tǒng)中所有其他線程(包含其他進(jìn)程中的那些線程)爭(zhēng)用資源。 一個(gè)進(jìn)程中的高優(yōu)先級(jí)線程可阻止其他進(jìn)程中的系統(tǒng)爭(zhēng)用范圍線程運(yùn)行。

進(jìn)程爭(zhēng)用范圍內(nèi)的線程在進(jìn)程內(nèi)進(jìn)行調(diào)度,這表示只在一個(gè)進(jìn)程內(nèi)的所有線程間進(jìn)行調(diào)度。 進(jìn)程爭(zhēng)用范圍通常表示由操作系統(tǒng)選擇要運(yùn)行的進(jìn)程,而進(jìn)程本身包含一個(gè)內(nèi)部調(diào)度程序來(lái)試圖針對(duì)進(jìn)程內(nèi)的線程實(shí)現(xiàn) POSIX 調(diào)度規(guī)則。
 四、測(cè)試源代碼

在linux下我們可以通過(guò)

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void*), void *arg);
來(lái)創(chuàng)建線程,但是如何設(shè)置線程的優(yōu)先級(jí)呢?
在討論這個(gè)問(wèn)題的時(shí)候,我們先要確定當(dāng)前線程使用的調(diào)度策略,posix提供了
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);函數(shù)來(lái)獲取所
使用的調(diào)度策略,它們是:
SCHED_FIFO, SCHED_RR 和 SCHED_OTHER。
我們可以使用
int sched_get_priority_max(int policy);
int sched_get_priority_min(int policy);
來(lái)獲取線程線程可是設(shè)置的最大和最小的優(yōu)先級(jí)值,如果調(diào)用成功就返回最大和最小的優(yōu)先級(jí)值,否則返回-1。
從我現(xiàn)在運(yùn)行的linux系統(tǒng)中,我使用下列程序獲取了對(duì)應(yīng)三種調(diào)度策略中的最大和最小優(yōu)先級(jí):
policy = SCHED_OTHER
Show current configuration of priority
max_priority = 0
min_priority = 0
Show SCHED_FIFO of priority
max_priority = 99
min_priority = 1
Show SCHED_RR of priority
max_priority = 99
min_priority = 1
Show priority of current thread
priority = 0
Set thread policy
Set SCHED_FIFO policy
policy = SCHED_FIFO
Set SCHED_RR policy
policy = SCHED_RR
Restore current policy
policy = SCHED_OTHER

我們可以看到
SCHED_OTHER是不支持優(yōu)先級(jí)使用的,而SCHED_FIFO和SCHED_RR支持優(yōu)先級(jí)的使用,他們分別為1和99,
數(shù)值越大
優(yōu)先級(jí)越高。 從上面的結(jié)果我們可以看出,如果程序控制線程的優(yōu)先級(jí),一般是用
pthread_attr_getschedpolicy來(lái)獲取系統(tǒng)使用的調(diào)度策略,如果是SCHED_OTHER的話(huà),表明當(dāng)前策略
不支持線程優(yōu)先級(jí)的使用,否則可以。當(dāng)然所設(shè)定的優(yōu)先級(jí)范圍必須在最大和最小值之間。我們可以通過(guò)
sched_get_priority_maxsched_get_priority_min來(lái)獲取。
可能網(wǎng)友會(huì)問(wèn),是否我們可以通過(guò)
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);來(lái)設(shè)定自己所需的
調(diào)度策略呢?我覺(jué)得是完全可以的(有些系統(tǒng)需要定義
_POSIX_THREAD_PRIORITY_SCHEDULING),只要
系統(tǒng)實(shí)現(xiàn)了對(duì)應(yīng)的調(diào)用策略。
說(shuō)了半天,我們還沒(méi)有說(shuō),在系統(tǒng)允許使用線程優(yōu)先級(jí)別的時(shí)候,如何設(shè)置優(yōu)先級(jí)別呢?
int pthread_attr_setschedparam(pthread_attr_t *attr,
const struct sched_param *param);
int pthread_attr_getschedparam(const pthread_attr_t *attr,
struct sched_param *param);

上面兩個(gè)函數(shù)分別用于設(shè)置線程的優(yōu)先級(jí),struct sched_param的定義如下
struct sched_param
{
int __sched_priority; //所要設(shè)定的線程優(yōu)先級(jí)
};


使用的測(cè)試程序:
#include <iostream>
#include <pthread.h>
#include <sched.h>
#include <assert.h>

using namespace std;

static int get_thread_policy( pthread_attr_t &attr )
{
        int policy;
        int rs = pthread_attr_getschedpolicy( &attr, &policy );
        assert( rs == 0 );
        switch ( policy )
        {
        case SCHED_FIFO:
                cout << "policy = SCHED_FIFO" << endl;
                break;

        case SCHED_RR:
                cout << "policy = SCHED_RR" << endl;
                break;

        case SCHED_OTHER:
                cout << "policy = SCHED_OTHER" << endl;
                break;

        default:
                cout << "policy = UNKNOWN" << endl;
                break;
        }

        return policy;
}

static void show_thread_priority( pthread_attr_t &attr, int policy )
{
        int priority = sched_get_priority_max( policy );
        assert( priority != -1 );
        cout << "max_priority = " << priority << endl;

        priority = sched_get_priority_min( policy );
        assert( priority != -1 );
        cout << "min_priority = " << priority << endl;
}

static int get_thread_priority( pthread_attr_t &attr )
{
        struct sched_param param;

        int rs = pthread_attr_getschedparam( &attr, &param );
        assert( rs == 0 );
        cout << "priority = " << param.__sched_priority << endl;

        return param.__sched_priority;
}

static void set_thread_policy( pthread_attr_t &attr,  int policy )
{
        int rs = pthread_attr_setschedpolicy( &attr, policy );
        assert( rs == 0 );
        get_thread_policy( attr );
}

int main( void )
{
        pthread_attr_t attr;
        struct sched_param sched;
        int rs;

        rs = pthread_attr_init( &attr );
        assert( rs == 0 );

        int policy = get_thread_policy( attr );

        cout << "Show current configuration of priority" << endl;
        show_thread_priority( attr, policy );

        cout << "Show SCHED_FIFO of priority" << endl;
        show_thread_priority( attr, SCHED_FIFO );

        cout << "Show SCHED_RR of priority" << endl;
        show_thread_priority( attr, SCHED_RR );

        cout << "Show priority of current thread" << endl;
        int priority = get_thread_priority( attr );

        cout << "Set thread policy" << endl;
        cout << "Set SCHED_FIFO policy" << endl;
        set_thread_policy( attr, SCHED_FIFO );
        cout << "Set SCHED_RR policy" << endl;
        set_thread_policy( attr, SCHED_RR );
        cout << "Restore current policy" << endl;
        set_thread_policy( attr, policy );


        rs = pthread_attr_destroy( &attr );
        assert( rs == 0 );

        return 0;
}

作者注:以上內(nèi)容純屬拼湊而成,如果你沒(méi)看明白,清直接看源地址。
直接引用文獻(xiàn)(不一定是作者出處):
1、
希望之光的博客
2、ITPUB論壇
3、IBM AIX文檔
4、中國(guó)源碼

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多