欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

操作系统进程调度(动态优先级调度算法---ready、waiting、running三态)

程序员文章站 2022-07-05 09:03:47
...

运行环境为 Ubuntu,Linux系统,C语言

本算法思想
首先创建进程的时候,就按照优先级高低把进程插入正确的顺序中。
之后的调度:运行完一个进程时间片,重新衡量它的优先级并插入到合适的地方。

一开始老师给的参考代码是只有ready和running态(最后面也贴出了此代码);老师做实验让我们加入waiting态,最好的方法应该是要把waiting态单独放在一个队列中,我当时觉得太麻烦了,就想直接放在末尾,奈何我想的太简单了,直接放末尾也超级麻烦,打算后期有时间写一下把waiting态单独放在队列中的代码!!!!!!

要考虑很多东西
1.如何保证waiting态始终在末尾?答:每次重新衡量running态进程时,必须要绕过waiting态,不管waiting态的优先级多高,放在waiting态前面。
2.如何保证唤醒的进程重新插入队列?答:先把该唤醒进程摘取出来,再按照优先级插入。还要考虑队列中是否只剩下waiting态的进程,专门加一个if条件,还有执行操作。

//三态(ready/running/waiting)


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <memory.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>


typedef struct pcb
{
    int pid;  /*Process ID*/
    int prior; /*进程优先级*/
    char status[10]; /*状态:ready,running,waiting*/
    int time;  //运行需要的时间
    struct pcb *next;
}PCB;


FILE *fp = NULL;


int sort(PCB **pstPCBHead,int *iNumProc);
int printProc(PCB *pstPCBHead);
int kbhit(void);
int insert_waiting(PCB **pstPCBHead);
int insert_ready(PCB **pstPCBHead,PCB **pstPCBNode);



int main()
{
    int iNumProc = 0; //进程的数量
    int i = 0;
    
    PCB *stPCBHead = NULL;  //头进程
    PCB *stPCB = NULL;  //链表指针
    PCB *stPCBFront = NULL; //进程前驱
    PCB *stPCBNode = NULL;
    
    char filename[128];
    
    memset(filename,0x00,sizeof(filename)); //初始化文件内容
    
    //sprintf(filename,"%s/schedule",getenv("HOME")); //filename=/HOME/schedule
    sprintf(filename,"%s", ".\\schedule"); //filename=/HOME/schedule
    
    if( (fp=fopen(filename,"w")) == NULL )
    {
        printf("Create log file failed!\n");
        return -1;
    }
    
    //输入进程的数量
    printf("Please input the number of process\n");
    scanf("%d",&iNumProc);
    
    //进程的数量必须大于0
    while( iNumProc <= 0)
    {
        printf("The number of process cann't be 0");
        printf("Please input the number of process again\n");
        scanf("%d",&iNumProc);      
    }
    
    for(i = 0;i < iNumProc;i++)
    {
        //创建进程结点
        stPCBNode=(PCB *)malloc(sizeof(PCB));
        if( (stPCBNode == NULL) )
        {
            printf("malloc memory failed!\n");
            return -1;
        }
        memset(stPCBNode,0x00,sizeof(PCB));
        
        //初始化进程的信息
        stPCBNode->pid = i;  //进程ID
        
        //输入进程优先级
        printf("Please input the prior of process[%d]\n",i);
        scanf("%d",&stPCBNode->prior);   
        /*进程的优先级必须大于0*/
        while( stPCBNode->prior < 0 )
        {
            printf("Process's prior must greater than 0\n");
            printf("Please input the prior of process[%d]\n",i);
            scanf("%d",&stPCBNode->prior);  
        }
        
        //输入进程运行时间
        printf("Please input the run time of process[%d]\n",i);
        scanf("%d",&stPCBNode->time);          
        /*进程的运行时间必须大于0*/
        while( stPCBNode->time < 0 )
        {
            printf("Process's run time must greater than 0\n");
            printf("Please input the run time of process[%d]\n",i);
            scanf("%d",&stPCBNode->time); 
        }       
        
        //初始化进程的状态为ready
        strcpy(stPCBNode->status,"ready"); 
        stPCBNode->next = NULL; 
        
        //连接新的进程结点
        if(stPCBHead == NULL)
        {
            stPCBHead = stPCBNode; //如果首结点为空,则让Node变成Head
            continue;
        }
        
        stPCB=stPCBHead;       //让stPCB指针指向Head
        stPCBFront=stPCBHead;  //让前驱指针stPCBFront指向Head
        
        while( stPCB != NULL && stPCB->prior >= stPCBNode->prior )  //循环查找该Node的前驱指针(即找到与Node的优先级相差最少,且比Node优先级大)
        {
            stPCBFront = stPCB;   //把该元素先假定为前驱Front
            stPCB = stPCB->next;  //指向下一个链表中的元素
        }
        
        
        if( stPCB == stPCBHead ) //优先级最高,插在最前面
        {
            stPCBNode->next = stPCBHead;  //先插在Head前面
            stPCBHead = stPCBNode;  //再把该节点变成Head
        }
        
        else if( stPCB == NULL ) //stPCB已经走到链表最后了,所以Front是stPCB的前一个,直接把Node插到尾部(Front的后面)
        {
            stPCBFront->next = stPCBNode; //添加到link的尾部
        }
        
        else  //插入到link (stPCB的前面,Front的后面)
        {
            stPCBNode->next = stPCB; 
            stPCBFront->next = stPCBNode;
        }
        
        printf("Create the process [%d] success\n",i);     
    } //for{ }
    
    
    
    fprintf(fp,"Create %d processes success\n",iNumProc);
    printf("In the begin of schedule,these process's queque\n");
    fprintf(fp,"Before Schedule\n");
    printProc(stPCBHead);
    
    sleep(1);
    
    //现在开始调度
    printf("Begin schedule\n");
    fprintf(fp,"Begin schedule\n");
    stPCB = stPCBHead;
    
    while( iNumProc > 0)
    {
        
        /* schedule from first process */
        if ( strcmp(stPCBHead->status, "ready") == 0 )
            strcpy(stPCBHead->status, "running");
        printProc(stPCBHead);
        
        if(strcmp((stPCBHead)->status, "running")==0) {
            stPCBHead->time--;
            stPCBHead->prior--;
        }



        
        //检测是否有按键s按下,如果有则把当前进程变成waiting态
        //while(kbhit() && (getchar() == 's' || getchar() == 'S') ) 
	int k=0;
	if( kbhit() ) k=getchar();

        if(k == 's')  
        { 
            printf("ss\n");
            strcpy(stPCBHead->status,"waiting");
            //printf("有按键按下了\n");
            printf("process %d waiting\n",stPCBHead->pid);
            setbuf(stdin,NULL);
            
            insert_waiting(&stPCBHead);  //直接把waiting进程放在末尾
            //break;
        }

        /* Update the the level of proccess which in ready status */
        for (stPCB=stPCBHead; stPCB != NULL; stPCB=stPCB->next)
        {
            if ( strcmp(stPCB->status, "ready") == 0)
            {
                stPCB->prior++;
            }
        }
        /*再次排序schedule*/
        sort(&stPCBHead,&iNumProc);  //排序link,删除time=0的进程    
        
        //检测是否有按键1-9按下,如果有则把第一个waiting状态的进程变成ready态,排序插入到其前驱的后面
        //while(kbhit() && (getchar() >= 0 && getchar() <= 9) )  
        if(k>='0' && k<='9')
        { 
            PCB *cur = NULL; //waiting态结点
            PCB *fro = NULL; //waiting态结点的前一个
            PCB *p = NULL; 
            printf("有数字按下了\n");
            
            setbuf(stdin,NULL);
            cur = stPCBHead;
            fro = stPCBHead;
            while( cur != NULL )
            {
                if( strcmp(cur->status,"waiting") == 0)
                {
                    strcpy(cur->status,"ready"); 
                    break;              
                } 
                fro = cur;
                cur = cur->next;
            }
            
            if(cur == stPCBHead) 
            {
              stPCBHead = stPCBHead->next;
              cur->next = NULL;
            }
            else {
	       p = cur->next;
	       fro->next = p;
	       cur->next = NULL;
            }

            insert_ready(&stPCBHead,&cur);  //把唤醒的进程重新按优先级顺序插入到队列中
            
        }
        

        //printProc(stPCBHead);
        
    } //while{ }
    
    return 0;
    
} //main{ }




/*============================子函数=================================================*/
int printProc(PCB *pstPCBHead)
{
    PCB *pstPCB = pstPCBHead;
    printf("----------------------------------------------------------------------------\n");
    printf("|  Process's ID  |  Process's prior   |  Process's Status  |  The time left  |  Current Process Addr  |  Next Process Addr |\n");
    printf("----------------------------------------------------------------------------\n");
    
    
    fprintf(fp,"----------------------------------------------------------------------------\n");
    fprintf(fp,"|  Process's ID  |  Process's prior   |  Process's Status  |  The time left  |  Current Process Addr  |  Next Process Addr |\n");
    fprintf(fp,"----------------------------------------------------------------------------\n");
    
    
    while( pstPCB != NULL )
    {
        sleep(1);
        
        printf( "|%10d|%16d|%22s|%15d|%24d|%20d|\n",pstPCB->pid,pstPCB->prior,pstPCB->status,pstPCB->time,(int)pstPCB,(int)pstPCB->next );
        printf( "----------------------------------------------------------------------------\n");
        
        fprintf( fp,"|%10d|%16d|%22s|%15d|%24d|%20d|\n",pstPCB->pid,pstPCB->prior,pstPCB->status,pstPCB->time,(int)pstPCB,(int)pstPCB->next );
        fprintf( fp,"----------------------------------------------------------------------------");
        
        pstPCB = pstPCB->next;
    }
    
    printf("\n\n");
    fprintf(fp,"\n\n");
    
    return 0;
}


int sort(PCB **pstPCBHead, int *iNumProc)
{
    PCB *pstPCB=NULL;
    PCB *pstPCBFront=NULL;
    int flag=0;
    
    pstPCB=(*pstPCBHead);
    pstPCBFront=(*pstPCBHead);
    
    if ( (*pstPCBHead)->time == 0 )
    {
        printf("Proccess [%d] run end!\n", pstPCBFront->pid);
        (*pstPCBHead) = (*pstPCBHead)->next;
        free(pstPCBFront);
        pstPCBFront=NULL;
        (*iNumProc)--;
        //return 0;
    }
    
    if ( (*iNumProc) <= 1 )
    {
        return 0;
    }
    
    if(strcmp((*pstPCBHead)->status,"running")==0)
        strcpy((*pstPCBHead)->status,"ready");
    
    while ( pstPCB != NULL && (*pstPCBHead)->prior <= pstPCB->prior && strcmp(pstPCB->status,"ready") == 0)
    {
        pstPCBFront = pstPCB;
        pstPCB=pstPCB->next;
        flag=1;
    }
    
    if ( pstPCB == NULL && flag==1)
    {
        if(strcmp((*pstPCBHead)->status, "running")==0)
            strcpy((*pstPCBHead)->status, "ready");
        pstPCBFront->next = (*pstPCBHead);
        *pstPCBHead = (*pstPCBHead)->next;
        pstPCBFront->next->next = NULL;
    }
    else if ( flag== 1)
    {
        if(strcmp((*pstPCBHead)->status, "running")==0)
            strcpy((*pstPCBHead)->status, "ready");
        pstPCBFront->next = (*pstPCBHead);
        (*pstPCBHead)= (*pstPCBHead)->next;
        pstPCBFront->next->next=pstPCB;
    }
    
    return 0;
}




//非阻塞检测按键函数
int kbhit(void)
{ 
struct termios oldt, newt;
int ch,oldf; 
tcgetattr(STDIN_FILENO, &oldt);
newt=oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
oldf=fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);

  ch=getchar();
  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  fcntl(STDIN_FILENO, F_SETFL, oldf);
  if(ch != EOF) { 
  ungetc(ch, stdin);
  return 1;
  } 
  return 0;
  }


int insert_waiting(PCB **pstPCBHead)
{
    PCB *pstPCB = NULL;
    PCB *pstPCBFront = NULL;
    PCB *p = NULL;
    
    pstPCB = (*pstPCBHead);
    pstPCBFront = (*pstPCBHead);
    

    
    if( strcmp( (*pstPCBHead)->status,"waiting") == 0) {
        while( pstPCB != NULL )  //把指针指到链表最后一个元素
        {
            pstPCBFront = pstPCB;   //把该元素先假定为前驱Front
            pstPCB = pstPCB->next;  //指向下一个链表中的元素
        }
        
        if( pstPCB == NULL) 
        {
            p = *pstPCBHead;
            (*pstPCBHead) = (*pstPCBHead)->next; //该Head的后面一个就是本次称霸的对象(因为本来就是按顺序排列的,老大下了,老二接手)
            pstPCBFront->next = p; //添加到link的尾部
            pstPCBFront = pstPCBFront->next;
            pstPCBFront->next = NULL;
        }
        
    } 
    
    return 0;
}

int insert_ready(PCB **pstPCBHead,PCB **pstPCBNode)
{
    PCB *pstPCB = NULL;
    PCB *pstPCBFront = NULL;
    
    pstPCB = (*pstPCBHead);
    pstPCBFront = (*pstPCBHead);
    
    if( strcmp((*pstPCBNode)->status,"ready") == 0) {
        printf("我正在把数字键唤醒的进程排序到队伍中\n");
 
        if((*pstPCBHead) == NULL) //说明该唤醒进程是最后一个进程
        {
           (*pstPCBHead) = *pstPCBNode;
           (*pstPCBHead)->next = NULL;
        }

       
        
        else 
        {
		while( pstPCB != NULL && pstPCB->prior >= (*pstPCBNode)->prior && strcmp(pstPCB->status,"ready") == 0)  //循环查找该Node的前驱指针(即找到与Node的优先级相差最少,且比Node优先级大)
		{
		    pstPCBFront = pstPCB;   //把该元素先假定为前驱Front
		    pstPCB = pstPCB->next;  //指向下一个链表中的元素
		}
		
		
		if( pstPCB == *pstPCBHead ) //优先级最高,插在最前面
		{
		    (*pstPCBNode)->next = *pstPCBHead;  //先插在Head前面
		    *pstPCBHead = *pstPCBNode;  //再把该节点变成Head
		}
		
		else if( pstPCB == NULL ) //stPCB已经走到链表最后了,所以Front是stPCB的前一个,直接把Node插到尾部(Front的后面)
		{
		    pstPCBFront->next = *pstPCBNode; //添加到link的尾部
		    //pstPCBFront->next->next = NULL;
		}
		
		else  //插入到link (stPCB的前面,Front的后面)
		{
		    (*pstPCBNode)->next = pstPCB; 
		    pstPCBFront->next = *pstPCBNode;
		}  
        } //else   
    } //if(status == ready){}
    
    return 0;
    
}





**

//两态(ready/running)

**

/***************************************************************************
输入进程数。输入每个进程优先级、运行时间,初始化为就绪态。
按照优先级优先算法调度进程运行,每运行一个时间片,运行时间减一、优先级减一。
进程在就绪队列中每等待一个时间片,其优先级加一。
****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <unistd.h>

typedef struct pcb
{
  int  pid;      /* Process ID */
  int  prior;    /* Priority of Processs*/
  char status[10]; /* value: ready,running */
  int  time;
  struct pcb *next;
} PCB;

FILE *fp=NULL;

int main()
{
  int iNumProc=0;
  int i = 0;
  
  PCB *stPCBHead=NULL;
  PCB *stPCB=NULL;
  PCB *stPCBFront=NULL;
  PCB *stPCBNode=NULL;
  
  char  filename[128];
  
  memset(filename, 0x00, sizeof(filename));
  
  sprintf(filename, "%s/schedule.txt", getenv("HOME"));
  if ( (fp=fopen(filename, "w")) == NULL)
  {
    printf("Create log file failed!\n");
    return -1;
  }
  
  /* Input the number of process */
  printf("Please input the number of process\n");
  scanf("%d", &iNumProc);
  
  /* Process number must great than 0 */
  while ( iNumProc <=0 )
  {
    printf("Ther number of process cann't be 0! \n");
    printf("Please input the number of process again\n");
    scanf("%d", &iNumProc);
  }
  
  for(i=0; i<iNumProc; i++)
  {
    /* Create process's node */
    stPCBNode=(PCB *)malloc(sizeof(PCB));
    if ( stPCBNode == NULL )
    {
      printf("malloc memory failed!\n");
      return -1;
    }
    memset(stPCBNode, 0x00, sizeof(PCB));
    
    /* Init process's information */
    stPCBNode->pid=i;    /* Process ID */
    printf("Please input ther prior of process[%d]\n", i);
    scanf("%d", &stPCBNode->prior);  /* Process's prior */
    
    while ( stPCBNode->prior < 0 )
    {
      printf("Process's prior must great than 0\n");
      printf("Please input ther run time of process[%d]\n", i);
      scanf("%d", &stPCBNode->prior);
    }
    
    printf("Please input ther run time of process[%d][%d]\n", i, __LINE__);
    scanf("%d", &stPCBNode->time);
    
    while ( stPCBNode->time < 0 )
    {
      printf("Process's run time must great than 0\n");
      printf("Please input ther run time of process[%d]\n", i);
      scanf("%d", &stPCBNode->time);
    }
    
    strcpy(stPCBNode->status, "ready");  /* Init the process's status ready */
    stPCBNode->next = NULL;
    
    /* Link the new process's node */
    if ( stPCBHead == NULL )
    {
      stPCBHead = stPCBNode;
      continue;
    }
    
    stPCB=stPCBHead;
    stPCBFront=stPCBHead;
    
    while ( stPCB != NULL && stPCB->prior >= stPCBNode->prior )
    {
      stPCBFront = stPCB;
      stPCB=stPCB->next;
    }
    
    if ( stPCB == stPCBHead )
    {
      stPCBNode->next = stPCBHead;
      stPCBHead=stPCBNode;
    }
    else if ( stPCB == NULL )  
    {
      stPCBFront->next = stPCBNode;    /* Add to the tail of the link */
    }
    else          /* insert into the link */
    {
      stPCBNode->next = stPCB;
      stPCBFront->next=stPCBNode;
    }
    
    printf("Create the process [%d] success\n", i);
  }
  fprintf(fp, "Create %d processes success\n", iNumProc);
  
  
  printf("In the begin of schedule, these process's queque\n");
  fprintf(fp, "Before Schedule\n");
  printProc(stPCBHead);
  
  sleep(1);
  
  /* Now Schedual */ 
  printf("Begin schedule\n");
  fprintf(fp, "Begin schedule\n");
  stPCB=stPCBHead;
  while ( iNumProc > 0 )
  {
    /* schedule from first process */
    if ( strcmp(stPCBHead->status, "ready") == 0 )
      strcpy(stPCBHead->status, "running");
    printProc(stPCBHead);
    
    stPCBHead->time--;
    stPCBHead->prior--;
    
    /* Update the the level of proccess which in ready status */
    for (stPCB=stPCBHead; stPCB != NULL; stPCB=stPCB->next)
    {
      if ( strcmp(stPCB->status, "ready") == 0 )
      {
        stPCB->prior++;
      }
    }
    
    /* sort the schedule again */
    sort(&stPCBHead, &iNumProc); /* Sort the link and delete which the process's time is 0 */
  }
  
  return 0;
}

int printProc(PCB *pstPCBHead)
{
  PCB *pstPCB=pstPCBHead;
  printf("------------------------------------------------------------------------------------------------------------\n");
  printf("| Process's ID   | Process's prior| Process's Stauts |The time left|Current Process Addr|Next Process Addr|\n");
  printf("------------------------------------------------------------------------------------------------------------\n");
  
  
  fprintf(fp, "-----------------------------------------------------------------------------------------------------------\n");
  fprintf(fp, "| Process's ID   | Process's prior| Process's Stauts |The time left|Current Process Addr|Next Process Addr|\n");
  fprintf(fp, "-----------------------------------------------------------------------------------------------------------\n");
  while ( pstPCB != NULL )
  {
    sleep(1);
  
    printf("|%16d|%16d|%18s|%13d|%20d|%17d|\n", pstPCB->pid,pstPCB->prior, pstPCB->status, pstPCB->time, (int)pstPCB, (int)pstPCB->next);
    printf("-----------------------------------------------------------------------------------------------------------\n");
  
    fprintf(fp, "|%16d|%16d|%18s|%13d|%20d|%17d|\n", pstPCB->pid, pstPCB->prior, pstPCB->status, pstPCB->time, (int)pstPCB, (int)pstPCB->next);
    fprintf(fp, "-----------------------------------------------------------------------------------------------------------\n");
    pstPCB=pstPCB->next;
  }
    
  printf("\n\n");
  fprintf(fp, "\n\n");
    
  return 0;
}

int sort(PCB **pstPCBHead, int *iNumProc)
{
  PCB *pstPCB=NULL;
  PCB *pstPCBFront=NULL;
  int flag=0;
  
  pstPCB=(*pstPCBHead)->next;
  pstPCBFront=(*pstPCBHead);
  
  if ( (*pstPCBHead)->time == 0 )
  {
    printf("Proccess [%d] run end!\n", pstPCBFront->pid);
    (*pstPCBHead) = (*pstPCBHead)->next;
    free(pstPCBFront);
    pstPCBFront=NULL;
    (*iNumProc)--;
    return 0;
  }
  
  if ( (*iNumProc) <= 1 )
  {
    return 0;
  }  
  
  while ( pstPCB != NULL && (*pstPCBHead)->prior <= pstPCB->prior )
  {
    pstPCBFront = pstPCB;
    pstPCB=pstPCB->next;
    flag=1;
  }
  
  if ( pstPCB == NULL && flag==1)
  {
    strcpy((*pstPCBHead)->status, "ready");
    pstPCBFront->next = (*pstPCBHead);
    *pstPCBHead = (*pstPCBHead)->next;
    pstPCBFront->next->next = NULL;
  }
  else if ( flag== 1)
  {
    strcpy((*pstPCBHead)->status, "ready");
    pstPCBFront->next = (*pstPCBHead);
    (*pstPCBHead)= (*pstPCBHead)->next;
    pstPCBFront->next->next=pstPCB;
  }
  
  return 0;
}







更新一下另外一种方法

不考虑每次都把他们按照优先级顺序排列,只要保证每次调度运行的进程的优先级最高即可。也就是把sort函数更改为找到优先级最高的ready进程并让它成为队列首部(Head)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>

typedef struct pcb {
    int pid;  //Process ID
    int prior; //进程优先级
    char status[10]; //状态:ready,running,waiting
    int time;  //运行需要的时间
    struct pcb *next;
}PCB;

FILE *fp = NULL;

int kbhit(void);
int printProc(PCB *pstPCBHead);
int sched(PCB **pstPCBHead, int *iNumProc);

int main()
{
    int iNumProc = 0; //进程的数量
    int i = 0;    
    PCB *stPCBHead = NULL;  //头进程
    PCB *stPCB = NULL;  //链表指针
    PCB *stPCBFront = NULL; //进程前驱
    PCB *stPCBNode = NULL;    
    char filename[128];
    
    memset(filename,0x00,sizeof(filename)); //初始化文件内容    
    sprintf(filename,"%s/schedule.txt",getenv("HOME")); // "/home/schedule.txt"
    
    if( (fp=fopen(filename,"w")) == NULL ) {
        printf("Create log file failed!\n");
        return -1;
    }
    
    //输入进程的数量
    printf("请输入进程数:\n");
    scanf("%d",&iNumProc);
    
    //进程的数量必须大于0
    while( iNumProc <= 0){
        printf("进程数须为正整数0");
        printf("请重新输入进程数\n");
        scanf("%d",&iNumProc);      
    }
    
    for(i = 0;i < iNumProc;i++) {
        //创建进程结点
        stPCBNode=(PCB *)malloc(sizeof(PCB));
        if( (stPCBNode == NULL) ){
            printf("分配堆内存失败!\n");
            return -1;
        }
        memset(stPCBNode,0x00,sizeof(PCB));
        
        //初始化进程的信息
        stPCBNode->pid = i;  //进程ID
        printf("请输入进程 [%d] 的优先级\n",i);
        scanf("%d",&stPCBNode->prior);   
        while( stPCBNode->prior < 1 ) {
            printf("优先级必须大于0\n");
            printf("请重新输入进度[%d] 的优先级\n",i);
            scanf("%d",&stPCBNode->prior);  
        }
        printf("请输入进程 [%d] 的运行时间\n",i);
        scanf("%d",&stPCBNode->time);          
        while( stPCBNode->time < 1 ) {
            printf("进行运行时间必须大于0\n");
            printf("请重新输入进程 [%d] 的运行时间\n",i);
            scanf("%d",&stPCBNode->time); 
        }
        strcpy(stPCBNode->status,"ready"); //初始状态为ready
        stPCBNode->next = NULL; 
        
        if(stPCBHead == NULL) {
            stPCBHead = stPCBNode; //队列头结点
            continue;
        }
        stPCB=stPCBHead;
        stPCBFront=stPCBHead;        
        while( stPCB != NULL && stPCB->prior >= stPCBNode->prior ) 
        {
            stPCBFront = stPCB;
            stPCB = stPCB->next;
        }        
        if( stPCB == stPCBHead )  {
            stPCBNode->next = stPCBHead;
            stPCBHead = stPCBNode; 
        }        
        else if( stPCB == NULL )
        {
            stPCBFront->next = stPCBNode;
        }        
        else {
            stPCBNode->next = stPCB; 
            stPCBFront->next = stPCBNode;
        }
        
        printf("创建进程 %d 成功\n",i);     
    }

    fprintf(fp,"创建进程 %d 成功\n",iNumProc);
    printf("调度之前,进程队列\n");
    fprintf(fp,"调度之前,进程队列\n");
    printProc(stPCBHead);
    
    sleep(1);
    
    //现在开始调度
    printf("开始调度\n");
    fprintf(fp,"开始调度\n");
    stPCB = stPCBHead;
    
    while( iNumProc > 0)
    {
        int k=0;
        
        //处理器分派给队首进程
        if ( strcmp(stPCBHead->status, "ready") == 0 )
            strcpy(stPCBHead->status, "running");
        printProc(stPCBHead);
        
        //调整队首进程优先级和运行时间
        if(strcmp((stPCBHead)->status, "running")==0) {
            stPCBHead->time--;
            stPCBHead->prior--;
        }
        
        //检测是否有按键s按下,如果有则把当前进程变成waiting态
        if(kbhit()) k=getchar();
        setbuf(stdin,NULL);
        if(k == 's') {
            strcpy(stPCBHead->status,"waiting");         
            printf("进程 %d 等待...\n",stPCBHead->pid);
            if(stPCBHead->next){ //头结点移到队尾
                PCB *t=stPCBHead;
                while(t && t->next) t=t->next;
                t->next=stPCBHead;
                stPCBHead=stPCBHead->next;
                t->next->next=NULL;                
            }
        }
        else if(k>='0' && k<='9'){ //注意:超过10个进程,不能处理
            PCB *t = stPCBHead;
	    k-='0';
            while(t && t->pid!=k) t=t->next;
            if(t && strcmp(t->status, "waiting")==0 ){
                strcpy(t->status, "ready");
                printf("进程 %d 回到就绪队列\n",t->pid);
            }       
        }
        
        // 提升剩余进程优先级 
        for (stPCB=stPCBHead; stPCB != NULL; stPCB=stPCB->next){
            if ( strcmp(stPCB->status, "ready") == 0)
                stPCB->prior++;
        }
        sched(&stPCBHead,&iNumProc); //调度器选择下一进程
    }
    
    return 0;
    
}

//============================子函数==========================
int printProc(PCB *pstPCBHead)
{
    PCB *pstPCB = pstPCBHead;
    printf("---------------------------------------------------------------------\n");
    printf("| 进程ID | 优先级 |  状态  | 剩余时间 | 当前进程地址 | 后继进程地址 |\n");
    printf("---------------------------------------------------------------------\n");    
    fprintf(fp,"--------------------------------------------------------------------\n");
    fprintf(fp,"| 进程ID | 优先级 |  状态 | 剩余时间 | 当前进程地址 | 后继进程地址 |\n");
    fprintf(fp,"--------------------------------------------------------------------\n");
    
    while( pstPCB != NULL ){
        sleep(1);        
        printf( "|%6d  |%6d  |%7s |%8d  |%14p|%14p|\n",pstPCB->pid,pstPCB->prior,pstPCB->status,pstPCB->time,pstPCB,pstPCB->next );
    	printf("---------------------------------------------------------------------\n");
        fprintf( fp,"|%6d  |%6d  |%7s |%8d  |%14p|%14p|\n",pstPCB->pid,pstPCB->prior,pstPCB->status,pstPCB->time,pstPCB,pstPCB->next );
    	fprintf(fp,"---------------------------------------------------------------------\n");
        pstPCB = pstPCB->next;
    }    
    printf("\n\n");
    fprintf(fp,"\n\n");
    
    return 0;
}

//优先级最大的ready进程放在队首
int sched(PCB **pstPCBHead, int *iNumProc)
{
    PCB * p, *q, t;
    
    if ( (*pstPCBHead)->time == 0 ){
        p=(*pstPCBHead);
        printf("进程 %d 运行结束,终止!\n", p->pid);
        (*pstPCBHead) = (*pstPCBHead)->next;
        free(p);
        p=NULL;
        (*iNumProc)--;
        if(*iNumProc==0) return 0;
    }
    
    if(strcmp((*pstPCBHead)->status,"running")==0)
        strcpy((*pstPCBHead)->status,"ready");
    
    p=(*pstPCBHead); //代表优先级最大的ready进程
    q=(*pstPCBHead)->next;
    while(q && strcmp(q->status,"ready")==0){
        if(p->prior<q->prior) p=q;
        q=q->next;
    }
    if(p!=(*pstPCBHead)){
        t=*(*pstPCBHead); //交换结点
        *(*pstPCBHead)=*p;
        *p=t;
        q=(*pstPCBHead)->next;  //交换链接指针
        (*pstPCBHead)->next=p->next;
        p->next=q;
    }    
    return 0;
}

//非阻塞检测按键函数
int kbhit(void)
{ 
    struct termios oldt, newt;
    int ch,oldf; 
    tcgetattr(STDIN_FILENO, &oldt);
    newt=oldt;
    newt.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
    oldf=fcntl(STDIN_FILENO, F_GETFL, 0);
    fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);

    ch=getchar();
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
    fcntl(STDIN_FILENO, F_SETFL, oldf);
    if(ch != EOF) { 
        ungetc(ch, stdin);
        return 1;
    } 
    return 0;
}