⊙-→棒棒糖ing .____`
作業系統原理分析要點
程序的排程時機與程序切換機制
-------------
排程時機
中斷處理過程(包括時鐘中斷、I/O中斷、系統呼叫和異常)中,直接呼叫schedule(),或者返回使用者態時根據need_resched標記呼叫schedule();
核心執行緒可以直接呼叫schedule()進行程序切換,也可以在中斷處理過程中進行排程,也就是說核心執行緒作為一類的特殊的程序可以主動排程,也可以被動排程;
使用者態程序無法實現主動排程,僅能通過陷入核心態後的某個時機點進行排程,即在中斷處理過程中進行排程
---------
程序的切換
程序切換 任務切換 上下文切換
1 switch_to 巨集 schedule() 程序描述符地址
2 程序切換-核心棧切換實施
A使用者態(中斷、異常、系統呼叫,使用者棧儲存在核心棧,ESP到棧底)--A核心態
A核心態(核心棧切換)--B核心態
B核心態(取出1使用者棧資訊、裝載暫存器)--B使用者態
====================================
i_addr[0]1483
i_addr[1]24
i_addr[2]225
i_addr[3]542
i_addr[4]2212
i_addr[5]98
i_addr[6]3321
i_addr[7]23
i_addr[8]123
i_addr[9]67---[n=10]
i_addr[10]326*
i_addr[11]756*
i_addr[12]226*
第326塊
……
[11]109
[12]954
[13]952
……
第756塊
[0]53**
[1]922**
……
第53塊
……
[211]863
[212]335
……
第922塊
……
[211]2312
[212]3276
……
假設某檔案的i-node結構及各級索引表如上所示,如果物理塊長度為X=1KB,塊號Y=4B
1.該檔案的讀寫指標指示地址為6820,給出該 地址所在的物理塊號和塊內地址
2.該檔案的讀寫指標指示地址為22675,給出 該地址所在的物理塊號和塊內地址
3.該檔案的讀寫指標指示地址為751155,給 出該地址所在的物理塊號和塊內地址
解:
a=log2(XKB/8bit)=log2(2^10)=10
0~9 有n=10
b=X KB/Y B=X*2^10/Y=2^8
(1)x1=6820
index=x1>>a=x1/(2^a)取整=6<n
w=x1&11……(a個1)=x1%(2^a)取餘數=676
物理塊號3321(PS:i_addr[6]3321)
塊內地址676(PS:w)
(2)x1=22675
index=x1>>a=x1/(2^a)取整=22
w=x1&11……(a個1)=x1%(2^a)取餘數=147<b
index=index-n=12
物理塊號954(PS:i_addr[10]326*[12]954 )
塊內地址147(PS:w)
(3)x1=751155
index=x1>>a=x1/(2^a)取整=733
w=x1&11……(a個1)=x1%(2^a)取餘數=563
index=index-n=723
index=index-b=467
index÷b=index2(商)……w2(餘數)
index2=1
w2=211
物理塊號2321(PS:i_addr[11]756*[1]922**[211]2312)
塊內地址563(PS:w)
=====================================
7 6 5 4 3 2 1 0
0_1_1_0_1_1_1_1
15 14 13 12 11 10 9 8
1__1___0__0__1__1_1_1
23 22 21 20 19 18 17 16
0__1__0__1__0__1___1__0
31 30 29 28 27 26 25 24
0__0__0__0__1__0___1__0
某靜態頁式儲存管理中,已知記憶體共有X=32塊 ,塊長度為Y=4K=2^12=4096,(假設單位一樣),當前位
示圖如上,程序P的虛擬地址空間大小為ADD=35655。
1.當前有幾個空閒塊[PS:數一下位示圖上有0] 14個
2.程序P共有幾頁[PS:ADD除以Y,商整數只入不捨 相當於
(ADD+Y-1)/Y取整數部分]
(35655+4K-1)/4K=9頁
3.根據位示圖,寫出程序P的頁表
[0]4
[1]7
[2]12
[3]13
[4]16
[5]19
[6]21
[7]23
[8]24
4.給定程序P的虛擬地址:9198和 ox9D8F,根據(3)分別計算對應的實體地址
十進位制的9198:
頁號p=9198/4K=2;頁內地址w=9198%4K=1006
塊號b=12(PS:[p]12)
實體地址=b*4K+1006=50158
十六進位制ox9D8F:
頁號p=1001 1101 1000 1111>>12=1001
p=9不小於9,越界
=======================================================
實驗一 併發程式設計
1.目的
在單處理器環境下,實現多工的核心是併發程式設計,程序的併發執行提高了CPU的利用率,使得CPU與裝置並行、裝置與裝置並行成為可能。但併發執行的一些程序之間需要互斥和同步的控制。
在應用系統開發中,幾乎都需要使用資料庫系統,在多使用者操作時,對資料庫中一些表的操作也需要互斥或同步。
2.要求
題目:在BACC環境下,對程式併發執行的實驗:(1)沒有控制時正確的程式執行的結果不正確;(2)BACC中PV操作的併發控制的實現。
要求:
(1)學習Windows命令介面中部分基本命令的使用
(2)BACC的使用:
(3)BACC中PV操作的併發控制的實現。
(4)將課堂和習題中的同步、互斥的併發程式設計的習題的設計與實現。
有併發控制的(兩種答案)
semaphore s=1;
int stack[20];
int top;
void pop(){
int free;
p(s);
free=stack[top];
top--;
cout<<"out:"<<free<<endl;
v(s);
}
void push(int free){
p(s);
top++;
stack[top]=free;
cout<<"in:"<<free<<endl;
v(s);
}
main()
{
int i;
for(i=0;i<20;i++)stack[i]=-1;
stack[0]=0;
stack[1]=156;
stack[2]=254;
stack[3]=129;
stack[4]=23;
top=4;
cobegin{
pop();push(100);}
cout<<"top_point="<<top<<endl;
for(i=0;i<=top;i++)
cout<<"stack["<<i<<"]="<<stack[i]<<endl;
}
2.同步關係
假定有三個程序R、W1、W2共享一個緩衝區B,而B每次只能存放一個整數。當緩衝區中無數時,程序R可以從輸入裝置上讀入一個整數並存入B中;若存到B中的數是奇數,則允許程序W1將其取出列印;若是偶數,則允許程序W2將其取出列印。另外規定:程序R必須等B中的數被取出列印後才能再存放下一個數,程序W1或W2對每次存入的數只能列印一次並且都不能從空的緩衝區中取數。請用PV操作實現R、W1和W2三個程序的併發執行。
semaphore S = 1, SO = 0, SE = 0;
int B;
void R()
{
int x;
cin >> x;
p(S);
B = x;
if (B % 2 == 1)
v(SO);
else v(SE);
}
void W1()
{
int y;
p(SO);
y = B;
v(S);
cout << "print odd:" << y << endl;
}
void W2()
{
int z;
p(SE);
z = B;
v(S);
cout << "print even:" << z << endl;
}
main()
{
cobegin{ R(); R(); W1(); W2(); }
}
實驗二 程序通訊
1.目的
程序通訊是多工協作的基礎,具有廣泛的應用。熟悉Linux的基於訊息佇列的程序通訊的系統呼叫,並實現一個簡單的C/S結構的例項。
2.要求
題目:Linux程序通訊及C/S結構應用。
(1)熟悉教材中有關程序通訊方式。
(2)熟悉Linux的使用(常用shell命令、VI、CC等)。
(3)熟悉Linux的訊息結構定義, msgget()、msgrcv(msgqid,…)、msgsnd(msgqid,…)的系統使用,C/S結構的工作過程 。
1.一個簡單C/S結構 實現①a*X+b=0求x②反轉字串
#define MSGKEY 1183
struct msgform {
long mtype;
int source_pid;
double a,b;
char opcode;
double result;
char fanzhuan[128];
char return_msg[128];
}msg;
int msgsize=sizeof(struct msgform)-sizeof(long);
int msgqid;
B1.C:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "msg_mycs.h"
main()
{
struct msgform msg;
int pid;
int i;
msgqid = msgget(MSGKEY,0777);
pid = getpid();
msg.opcode != '1';
for(;msg.opcode!='q';){
printf("opcode=(1 for a*?+b=0; 2 forfanzhuan;q for EXIT)");
msg.opcode=getchar();
while(msg.opcode=='\n')msg.opcode=getchar();
if (msg.opcode == '1' || msg.opcode == '2')
{
if (msg.opcode == '1')
{
printf("a=");
scanf("%lf", &msg.a);
printf("b=");
scanf("%lf",&msg.b);
}
else{
printf("the string=");
scanf("%s", msg.fanzhuan);
}
msg.source_pid=pid;
msg.mtype=1;
msg.return_msg[0]=0;
msgsnd(msgqid,&msg,msgsize,0);
msgrcv(msgqid,&msg,msgsize,pid,0);
printf("client: receive from pid=%d\n",msg.source_pid);
if(msg.opcode=='1')
printf("%.2f* %.2f + %.2f = 0\n",msg.a,msg.result,msg.b);
else
printf("%s\n",msg.return_msg);
}
}
}
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "msg_mycs.h"
main()
{
struct msgform msg;
int pid;
int i;
msgqid = msgget(MSGKEY,0777);
pid = getpid();
msg.opcode != '1';
for(;msg.opcode!='q';){
printf("opcode=(1 for a*?+b=0; 2 forfanzhuan;q for EXIT)");
msg.opcode=getchar();
while(msg.opcode=='\n')msg.opcode=getchar();
if (msg.opcode == '1' || msg.opcode == '2')
{
if (msg.opcode == '1')
{
printf("a=");
scanf("%lf", &msg.a);
printf("b=");
scanf("%lf",&msg.b);
}
else{
printf("the string=");
scanf("%s", msg.fanzhuan);
}
msg.source_pid=pid;
msg.mtype=1;
msg.return_msg[0]=0;
msgsnd(msgqid,&msg,msgsize,0);
msgrcv(msgqid,&msg,msgsize,pid,0);
printf("client: receive from pid=%d\n",msg.source_pid);
if(msg.opcode=='1')
printf("%.2f* %.2f + %.2f = 0\n",msg.a,msg.result,msg.b);
else
printf("%s\n",msg.return_msg);
}
}
}
2.一個簡單C/S結構的基金賬戶管理
#define MSGKEY 1183
struct msgform {
long mtype;
int source_pid;
char nameid[10],password[10];
char opcode;
double result;
char return_msg[100];
}msg;
int msgsize=sizeof(struct msgform)-sizeof(long);
int msgqid;
#include <stdlib.h> /*如果沒有這個會提示貌似是 identifier or ‘(’ before 甚麼甚麼的錯誤*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/ioctl.h>/*如果沒有這個會提示 define NULL 的錯誤*/
#include "msg_mycs.h"
struct usr
{
char name[10];
char pass[10];
double money;
struct usr *next;
}*head;
int registerr(struct msgform m);/*這個自己定義的函式名,本來是register,應該是標頭檔案裡面有個這個名字的,所以我就弄了另一個就ok了*/
struct usr* findbyName(struct msgform m);
main()
{
int i,j;
extern cleanup();
for(i=0;i<20;i++)
signal(i,cleanup);
msgqid = msgget(MSGKEY,0777|IPC_CREAT);
head= NULL;
struct usr *pointlist;
pointlist = NULL;
for(;msg.opcode!='q';)
{
printf("server pid= %d is ready (msgqid=%d)... \n",getpid(),msgqid);
msgrcv(msgqid,&msg,msgsize,1,0);
printf("server: receive from pid=%d\n",msg.source_pid);
switch(msg.opcode){
case '1':
j=registerr(msg);
if (j == 0)strcpy(msg.return_msg, "the account already exists ");
else strcpy(msg.return_msg, "register successfull");
break;
case '2':
pointlist=findbyName(msg);
if (pointlist == NULL)strcpy(msg.return_msg, "the account you required doesnot exist or password error");
else strcpy(msg.return_msg, "sign in successfull");
break;
case '3':if (pointlist != NULL )
{
pointlist->money+=msg.result;
strcpy(msg.return_msg, "deposit successfull");
} else strcpy(msg.return_msg, "error,please ask for help");
break;
case '4':
if (pointlist != NULL)
{
if (msg.result > 0 && pointlist->money > msg.result)
{
pointlist->money -= msg.result;
msg.result=pointlist->money;
strcpy(msg.return_msg, "withdraw successfull");
}
else strcpy(msg.return_msg, " insufficient balance ");
}
else strcpy(msg.return_msg, "withdraw error ");
break;
case '5':
if (pointlist!= NULL )
{
msg.result=pointlist->money ;
strcpy(msg.return_msg, "account balance");
}
else strcpy(msg.return_msg, "operation error ");
break;
}
msg.mtype=msg.source_pid;
msg.source_pid=getpid();
msgsnd(msgqid,&msg,msgsize,0);
}
pointlist = NULL;
printf("server eixt by client pid=%d\n",msg.mtype);
}
struct usr* findbyName(struct msgform m)
{
struct usr * tmp_node;
tmp_node = head;
while (tmp_node!= NULL)
{
if ((strcmp(tmp_node->name, m.nameid) == 0) &&( strcmp(tmp_node->pass, m.password) == 0)){return tmp_node;
}tmp_node = tmp_node->next;
}
return NULL;
}
int registerr (struct msgform m)
{
struct usr* tmp_node;
tmp_node = head;
while (tmp_node != NULL)
{
if (strcmp(tmp_node->name, m.nameid) == 0)return 0;
tmp_node = tmp_node->next;
}
tmp_node = malloc(sizeof(struct usr));
strcpy(tmp_node->name, m.nameid);
strcpy(tmp_node->pass, m.password);
tmp_node->money = m.result;
tmp_node->next = head;
head = tmp_node;
return 1;
}
cleanup()
{
msgctl(msgqid,IPC_RMID,0);
exit(0);
}
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "msg_mycs.h"
main()
{
struct msgform msg;
int pid;
int i;
msgqid = msgget(MSGKEY,0777);
pid=getpid();
msg.opcode='1';
for(;msg.opcode!='q';){
printf("1:zhuce\n 2:dengru\n 3:cunk \n 4: quk \n 5:chaxun \n q:tuichu \n ");
msg.opcode=getchar();
while(msg.opcode=='\n')msg.opcode=getchar();
if(msg.opcode=='1'||msg.opcode=='2'){
printf("user:");
scanf("%s",&msg.nameid);
printf("password:");
scanf("%s",&msg.password);} else
if(msg.opcode=='3') { printf("cun monney:");
scanf("%lf",&msg.result);
} else if(msg.opcode=='4'){printf("qu monney:");
scanf("%lf",&msg.result);}
if(msg.opcode=='1'||msg.opcode=='2'||msg.opcode=='3'||msg.opcode=='4'||msg.opcode=='5')
{
msg.source_pid=pid;
msg.mtype=1;
msg.return_msg[0]=0;
msgsnd(msgqid,&msg,msgsize,0);
msgrcv(msgqid,&msg,msgsize,pid,0);
printf("client: receive from pid=%d\n",msg.source_pid);
switch (msg.opcode)
{
case '1':
case '2':
printf("%s\n", msg.return_msg);
break;
case '3':
case '4':
case '5':
printf("%s\n $=%lf\n", msg.return_msg, msg.result);
break;
}
}
}
}