私は、オペレーティングシステム(VI)の書き方を学んでいた:スケジューリングプロセス

序文

マルチプロセスの導入は、実際には、前後に処理を切り替えることであるため、プロセス間のスケジューリング問題が存在することになります。しかし、現実には実行可能なプロセス間の限られた資源のカーネルサブシステムのプロセッサ時間の配分です。

いくつかの簡単なCPUスケジューリングアルゴリズム

  • まず、是非、まず(FCFS)添え

これは、実際にFIFOキュー、まず最初に、来実装されているプロセスです。CPUがアイドル状態のときに、それはプロセスがキューの先頭に位置しているに割り当てられ、そしてこのプロセスを実行されるキューから削除されます。FCFSスケジューリングシンプルかつ容易に理解コーディング。

全体のタスクキューを完了するために必要な所要時間が非常に長いので、しかし、プロセスの必要性とユーザーとの対話は、このスケジューリングアルゴリズムは、非常に悪い経験になります

しかし、FCFSスケジューリングアルゴリズムは、ノンプリエンプティブです。CPUは、剥離、即ち、プログラム終了要求またはI / OをするまでCPUまでCPUを使用するプロセスに割り当てられると

  • 最短仕事ファースト(SJF)

スケジューリングアルゴリズムがうまくいくSJFが短い又は短いプロセスの優先順位スケジューリングアルゴリズムを指し、各プロセスは、動作中に推定時間ジョブを計算する最短時間に関連付けられ、その推定を実行します。これは、ターンアラウンドタイムを短縮することができます

最短ジョブ優先(SJF)スケジューリングアルゴリズムは、その次のCPUの長さは、各プロセスを関連付ける実行します。CPUがアイドル状態になった場合、それは最短のCPUによって実行されると処理が割り当てられます。だから、FCFSはCPUで処理することができた場合に2つのプロセスが同じ長さを持って実行します。

  • RR

このアルゴリズムでは、時間の小さな単位は、時間またはタイムスライスの量として定義されます。タイムスライスのサイズは、通常、10〜100ミリ秒です。循環キューとしてレディキュー。スケジューラ・ループのCPUの全体レディキュー、各プロセスのノーつ以上の割り当てられたCPUタイムスライス。

RRスケジューリングを実現するために、我々は再びレディキューFIFOキュー・プロセスとして扱われます。新しいプロセスはレディキューの最後尾に追加しました。CPUスケジューラはレディキューから最初のプロセスを選択し、タイムスライスした後、タイマ割り込みを設定し、最終的にプロセスを派遣。

妥協スケジューリングアルゴリズム

多くのプロセスで実行している、といくつかは、プロセスの応答時間を懸念している、とスケジューリングアルゴリズムを妥協する必要があるので、いくつかは、ターンアラウンドタイムの​​プロセスをより懸念しているが、妥協がどのように質問です。

Linux0.11スケジューリングアルゴリズム

スケジュール

Linux0.11スケジュールは、スケジューリングアルゴリズムの中で最も重要ですが、非常に単純な

  • task_struct構造の過程を説明するために使用されます

    カウンタtask_structスケジューリングアルゴリズムは、両方が割り当てられたタイムスライスを表すために使用され、プロセスの優先度を表すために使用される、キーの妥協であります

  • まず、タスクのタスクの配列から最後のサイクルは、いくつかのフィールドを検出し始めます

    タイミングがあまりにもアラームタスクの設定で、(アラーム<単位jiffies)の有効期限が切れている場合、中央信号伝送SIGALARMのSIGALRM信号のビットマップ、すなわちタスク。そして、明確なアラーム。後で言及する量に関連するいくつかの信号があります。

  • それに切り替えるプロセス、プロセスの実行時間最小couter、の最大値を見つけます

  • 完了すると、バック回転の実装を再割り当てられたタイムスロットであり、回転のためにこの時間が進行されている、タイムスライスは初期値に設定されますが、プロセスをブロック人のために、行われる、タイムスライスを増加させます妥協のスケジュール。

void schedule(void)
{
    int i,next,c;
    struct task_struct ** p;

/* check alarm, wake up any interruptible tasks that have got a signal */

    for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
        if (*p) {
            if ((*p)->alarm && (*p)->alarm < jiffies) {
                    (*p)->signal |= (1<<(SIGALRM-1));
                    (*p)->alarm = 0;
                }
            if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
            (*p)->state==TASK_INTERRUPTIBLE)
                (*p)->state=TASK_RUNNING;
        }

/* this is the scheduler proper: */

    while (1) {
        c = -1;
        next = 0;
        i = NR_TASKS;
        p = &task[NR_TASKS];
        while (--i) {
            if (!*--p)
                continue;
            if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
                c = (*p)->counter, next = i;
        }
        if (c) break;
        for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
            if (*p)
                (*p)->counter = ((*p)->counter >> 1) +
                        (*p)->priority;
    }
    switch_to(next);
}

その中に

私たちはsched_initの見方では、この初期化ルーチンカーネルのスケジューラ機能は、いくつかの混乱と記述子を初期化することです

  • まず、コールset_tss_descとプロセスのTSSとLDT 0のset_ldt_descセット

  • 明確な権限と配列の記述子テーブルエントリ

  • 初期8253タイマーの後

  • 最後に、クロック割り込みを設定し、システムコールを中断

void sched_init(void)
{
    int i;
    struct desc_struct * p;

    if (sizeof(struct sigaction) != 16)
        panic("Struct sigaction MUST be 16 bytes");
    set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));
    set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
    p = gdt+2+FIRST_TSS_ENTRY;
    for(i=1;i<NR_TASKS;i++) {
        task[i] = NULL;
        p->a=p->b=0;
        p++;
        p->a=p->b=0;
        p++;
    }
/* Clear NT, so that we won't have troubles with that later on */
    __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
    ltr(0);
    lldt(0);
    outb_p(0x36,0x43);      /* binary, mode 3, LSB/MSB, ch 0 */
    outb_p(LATCH & 0xff , 0x40);    /* LSB */
    outb(LATCH >> 8 , 0x40);    /* MSB */
    set_intr_gate(0x20,&timer_interrupt);
    outb(inb_p(0x21)&~0x01,0x21);
    set_system_gate(0x80,&system_call);
}

集合記述子

アクションは、実際に_set_tssldt_desc各ビットのセット記述子であります

#define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),"0x89")
#define set_ldt_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),"0x82")

#define _set_tssldt_desc(n,addr,type) \
__asm__ ("movw $104,%1\n\t" \
    "movw %%ax,%2\n\t" \
    "rorl $16,%%eax\n\t" \
    "movb %%al,%3\n\t" \
    "movb $" type ",%4\n\t" \
    "movb $0x00,%5\n\t" \
    "movb %%ah,%6\n\t" \
    "rorl $16,%%eax" \
    ::"a" (addr), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \
     "m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) \
    )

割り込みを設定します。

#define _set_gate(gate_addr,type,dpl,addr) \
__asm__ ("movw %%dx,%%ax\n\t" \
    "movw %0,%%dx\n\t" \
    "movl %%eax,%1\n\t" \
    "movl %%edx,%2" \
    : \
    : "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
    "o" (*((char *) (gate_addr))), \
    "o" (*(4+(char *) (gate_addr))), \
    "d" ((char *) (addr)),"a" (0x00080000))

#define set_intr_gate(n,addr) \
    _set_gate(&idt[n],14,0,addr)

#define set_system_gate(n,addr) \
    _set_gate(&idt[n],15,3,addr)    

概要

これは非常に単純な、スケジューリング・アルゴリズムでLinux0.11に見えたが、それは、応答時間の世話をするだけでなく、ターンアラウンドタイムの​​世話をすることで、主要なです。

そして、ビットの初期化ルーチンカーネルスケジューラを入れて、実際には、前のセットに応じて、いくつかの記述子が言うと割り込み処理します

おすすめ

転載: www.cnblogs.com/secoding/p/11422525.html