序文
マルチプロセスの導入は、実際には、前後に処理を切り替えることであるため、プロセス間のスケジューリング問題が存在することになります。しかし、現実には実行可能なプロセス間の限られた資源のカーネルサブシステムのプロセッサ時間の配分です。
いくつかの簡単な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に見えたが、それは、応答時間の世話をするだけでなく、ターンアラウンドタイムの世話をすることで、主要なです。
そして、ビットの初期化ルーチンカーネルスケジューラを入れて、実際には、前のセットに応じて、いくつかの記述子が言うと割り込み処理します