【操作系统】进程调度与同步

一、实验目的

 了解操作系统中常见的进程调度算法
 了解在linux中利用多线程模拟实现FCFS,SJF,RR的调度过程。
 了解进程同步的特点,掌握利用信号量实现进程间同步的的方法。
 了解哲学家问题中进程之间的相互制约关系,能够合理的设置信号量。
 了解Linux系统下创建多线程的原理及使用方法,模拟哲学家问题的实现。

二、实验项目内容

进程调度:
本实验利用线程模拟进程,实现进程间的调度算法。主要有以下内容:
 创建主线程,主线程的工作包括:创建子线程,保存子线程的虚拟PCB ;并负责子线程的调度。调度的基本时间单位为1s。
 主线程创建20个子线程,分别实现FCFS调度、SJF调度、RR调度、优先级调度和多级队列调度,并且计算每个调度的平均等待时间。(其中优先级调度和多级队列调度为选做)。
 对于每个子线程,在其运行期间,输出其占用的时间标号(例如,第3个线程占用了第10秒的CPU时间,输出为:“Thread3:10”)。

进程同步:
 1 根据哲学家进程间的相互制约关系,设置合理的信号量及信号量初值。
 2 创建5个线程,分别模拟5个哲学家进程。
 3 在哲学家线程之间通过对信号量的P,V操作,实现线程之间的同步关系。

三.试验过程及算法
(一) 进程调度

【操作系统】进程调度与同步_第1张图片

实验步骤计算法:
1. 创建主线程,主线程的工作包括:创建子线程,保存子线程的虚拟PCB ;并负责子线程的调度。调度的基本时间单位为1s。
2. 主线程创建20个子线程,分别实现FCFS调度、SJF调度、RR调度、优先级调度和多级队列调度,并且计算每个调度的平均等待时间。
3. 对于每个子线程,在其运行期间,输出其占用的时间标号

(二) 进程同步

【操作系统】进程调度与同步_第2张图片

实验步骤计算法:
1 根据哲学家进程间的相互制约关系,设置合理的信号量及信号量初值。
2 创建5个线程,分别模拟5个哲学家进程。
3 在哲学家线程之间通过对信号量的P,V操作,实现线程之间的同步关系。

三、实验程序代码:
(一)进程调度程序源码
#include
#include
#include
#include
#include
#include

#define THREADNUM 20 //子线程数量

pthread_mutex_t DeviceMutex ;
//线程的虚拟PCB信息 
struct VirtualPCB
{
int tid;
int handlePriority;
int arrivetime;
int waittime;
int runtime;
int visited;
int tempruntime;
}PCBs[THREADNUM]; 

//初始化PCB
void initPCB()
{
int n;
srand(time(NULL));
for(n =0;n//用线程创建序号作为虚拟进程id
PCBs[n].tid = n + 1;
//用随机数随机产生虚拟PCB的值
PCBs[n].handlePriority = 1 + rand()%19;
PCBs[n].tempruntime=PCBs[n].runtime = 1 + rand()%19;
//默认进程按创建顺序依次在0时刻到达
PCBs[n].arrivetime = 0;
PCBs[n].waittime = 0;
PCBs[n].visited =0;
}
}

//子线程功能实现
void *t_print(void *arg)
{
int n = *(int *)arg;//get argument
while(1)
{
pthread_mutex_lock(&DeviceMutex);
printf("thread%-2d: ",n);
printf("tid:%2d Priority:%2d runtime:%2d \n",PCBs[n-1].tid,PCBs[n-1].handlePriority,PCBs[n-1].runtime);
pthread_mutex_unlock(&DeviceMutex);
sleep(1);
break;
}
pthread_exit(0);
}

//计算FCFS(First come first service)
void handleFCFS()
{
printf("\n-----------FCFS-----------\n");
int i,j;
int start = 0;
float waittime = 0;
float avwait = 0;
for(i=0;i2;i++)
{
for(j=0;jif(PCBs[j].arrivetime==i && PCBs[j].visited==0){
printf("Thread: %2d Start: %3d Runtime: %2d\n",PCBs[j].tid,start,PCBs[j].runtime);
waittime = waittime + (float)start;
start = start + PCBs[j].runtime;
PCBs[j].visited=1;
}
}
}
avwait = waittime / (float)THREADNUM;
printf("Total waitting time : %f\n",waittime);
printf("Average waitting time : %f\n",avwait);
}

//计算SJF(Shortest job first)
void handleSJF()
{
for(int k=0 ;k0;
}
printf("\n-------------SJF-------------\n");
int i,j;
int start = 0;
float waittime = 0;
float avwait = 0;
for(i=1;ifor(j=0;jif(PCBs[j].runtime==i && PCBs[j].visited==0){
printf("Thread: %2d Start: %3d Runtime: %2d\n",PCBs[j].tid,start,PCBs[j].runtime);
waittime = waittime + (float)start;
start = start + PCBs[j].runtime;
PCBs[j].visited=1;
}
}
}
avwait = waittime / (float)THREADNUM;
printf("Total waitting time : %f\n",waittime);
printf("Average waitting time : %f\n",avwait);
}

//计算Priority
void handlePriority()
{
for(int k=0 ;k0;
}
printf("\n-----------Priority-------------\n");
int i,j;
int start = 0;
float waittime = 0;
float avwait = 0;
for(i=1;ifor(j=0;jif(PCBs[j].handlePriority==i && PCBs[j].visited==0){
printf("Thread: %2d Start: %3d Runtime: %2d\n",PCBs[j].tid,start,PCBs[j].runtime);
waittime = waittime + (float)start;
start = start + PCBs[j].runtime;
PCBs[j].visited=1;
}
}
}
avwait = waittime / (float)THREADNUM;
printf("Total waitting time : %f\n",waittime);
printf("Average waitting time : %f\n",avwait);
}

//计算RR(Round R)
void handleRR(int r)
{
printf("\n--------------RR-------------\n");
int start = 0;
float waittime = 0;
float avwait = 0;
for(int i=0;iint totaltime = totaltime + PCBs[i].runtime;
PCBs[i].visited=0;
}
for(int j=0;j<20*THREADNUM;j=j+r)
{
int k = (j%(20*r))/r;
if(PCBs[k].tempruntime > 0){
int tepruntime = r;
if(PCBs[k].tempruntime-r<=0){
tepruntime = PCBs[k].tempruntime;
PCBs[k].waittime=start + tepruntime - PCBs[k].runtime;
}
printf("Thread: %2d Start: %3d Runtime:%2d \n",PCBs[k].tid, start,tepruntime);
start = start + tepruntime;
PCBs[k].tempruntime=r;
}
}
for(int m=0;mfloat)THREADNUM;
printf("Total waitting time : %f\n",waittime);
printf("Average waitting time : %f\n",avwait);
}

//Main thread execute function to create 20 children threads
void* Children(void* vargp)
{
int ret[THREADNUM];
initPCB();
pthread_t tid[THREADNUM];
pthread_mutex_init(&DeviceMutex,NULL);
int i,j;

for(i=0;iint k =i+1;

ret[i] = pthread_create(&tid[i],NULL,&t_print, &k);
if(ret[i] == 0) {
sleep(1);
}
else{ 
printf("thread_%2d failed!\n",i+1);

} 
}
for(j=0;j0);
}

int main()
{
int ret1;
//创建主线程
pthread_t tid1;
ret1 = pthread_create(&tid1,NULL,&Children,NULL);
if(ret1 == 0) 
{
printf("creating child threads...\n...\n");
sleep(20);
}
else{ 
printf("Create Main Thread failed!\n");

} 

handleFCFS();
handleSJF();
handlePriority();
printf("Please enter RR time:");
int rr;
//获取RR时间
scanf("%d",&rr);
handleRR(rr);
return 0;
}
(二)进程同步程序源码
#include  
#include 
#include  
#define N 5 //哲学家数量
#define LEFT (i+N-1)%N //第i位哲学家的左边 
#define RIGHT (i+1)%N //第i位哲学家的右边

//哲学家状态 
int state[N];
#define STATE_THINKING 11 //思考
#define STATE_EATING 12 //吃饭
#define STATE_HUNGRY 13 //饥饿
//信号量 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER, s[N]; 

//检查哲学家状态 
void checkState(int i) 
{
//当哲学家饥饿,且左右两边的哲学家均不在吃饭状态时 
if (state[i] == STATE_HUNGRY
&& state[LEFT] != STATE_EATING&& state[RIGHT] != STATE_EATING) 
{ 
//哲学家开始吃饭
state[i] = STATE_EATING; 
pthread_mutex_unlock(&s[i]); 
} 
} 
void takeForks(int i) 
{ 
pthread_mutex_lock(&mutex); 
//当哲学家饥饿
state[i] = STATE_HUNGRY; 
checkState(i); 
pthread_mutex_unlock(&mutex); 
pthread_mutex_lock(&s[i]); 
} 
void putForks(int i)
{ 
pthread_mutex_lock(&mutex); 
//当哲学家思考
state[i] = STATE_THINKING; 
checkState(LEFT); 
checkState(RIGHT); 
pthread_mutex_unlock(&mutex); 
} 
//哲学家思考 
void think(int i) 
{ 
printf("philosopher %d is thinking...\n", i); 
//等待一段时间 
sleep(3); 
} 
//哲学家吃饭 
void eat(int i) 
{ 
printf("philosopher %d is eating...\n", i); 
//等待一段时间
sleep(2); 
} 
//哲学家线程的实现 
void* creatPhilosopher(void* vargp) 
{ 
int i = *(int*)vargp; 
while (1) 
{ 
think(i); 
takeForks(i); 
eat(i); 
putForks(i); 
} 
return NULL; 
} 
int main() 
{ 
int i; 
pthread_t tidp[N]; 
//创建5个子线程模拟哲学家行为
for (i = 0; i < N; i++) 
pthread_create(&tidp[i], NULL, creatPhilosopher, (void*)(&i)); 
for (i = 0; i < N; i++)
//等待子线程结束 
pthread_join(tidp[i], NULL); 
return 0; 
} 
四、实验结果:
(一) 进程调度

a) 结果
【操作系统】进程调度与同步_第3张图片
上图初始化20个子线程,并显示输出其属性
【操作系统】进程调度与同步_第4张图片
上图计算FCFS调度的时间,并显示输出时间刻度
【操作系统】进程调度与同步_第5张图片
上图计算SJF调度的时间,并显示输出时间刻度
【操作系统】进程调度与同步_第6张图片
上图计算Priority调度的时间,并显示输出时间刻度
【操作系统】进程调度与同步_第7张图片
上图计算RR调度的时间,输入RR=5,并显示输出时间刻度

b) 分析
实验结果如上图所示,分别显示输出20个子线程信息,并分别计算了FCFS、SJF、Priority、RR调度机制的运行时间和等待时间,4种调度均采用同一个样本,便于统计和比较。

(二) 进程同步

a) 结果
【操作系统】进程调度与同步_第8张图片

b) 分析
程序创建5个子线程模拟5个哲学家的行为,分别标号0~4,程序中哲学家思考的时间比吃饭的时间要长,由于实验结果较长,截取其中一部分分析,哲学家们并未出现相邻同时吃饭的问题和死锁,但程序初始会出现哲学家同时思考的现象,程序结果符合实验要求。

你可能感兴趣的:(操作系统,操作系统,多线程,linux)