Linux是多用户、多任务的操作系统。在这样的环境中,各种计算机资源的分配和管理都是以进程为单位进行的。
Linux操作系统包括三种不同类型的进程:
1)交互进程:一种由Shell启动的进程。交互进程既可在前台进行,也可在后台运行。前者称为前台进程,后者为后台进程。前台进程可与用户通过Shell进行交互。
2)批处理进程:与终端没有联系,是系列进程,即多个进程按照指定的方式执行。
3)守护进程:运行在后台的一种特殊进程,在系统启动时启动,并在后台运行。守护进程本身不在屏幕上显示任何信息,但会在后台悄悄地为用户服务,例如运行的网络服务程序。
在操作系统中,进程是指运行中的程序实体。此外还包括这个运行的程序所占据的所有系统资源,如CPU、设备、内存、网络资源等。Linux中,可以用ps命令得到当前系统中进程的列表。
在Linux中每个进程在被创建时都会分配一个结构体 task_struct,即进程控制块PCB。
task_struct结构体虽然庞大而复杂,但其中信息可以归为以下几类:
1)标识信息:唯一标识一个进程
2)状态信息
1.运行:进程处于运行状态或者准备运行状态。
2.等待:进程在等待一个事件或资源。又分为两类,可中段(可被信号中断),不可中断(由于硬件原因而等待)
3.停止:进程处于停止状态。
4.跟踪:进程正在被跟踪。
5.僵死:进程已终止。
6.死亡:表示进程处于退出过程,它所占的所有资源都会被回收。
3)调度信息:调度进程所需要的信息,如:进程类型、优先级、允许进程执行的时间片。
进程调度就是进程程序按照一定的策略,动态地把CPU分配给处于就绪队列中的某个进程。
Linux操作系统中存在两类进程,即普通进程和实时进程。任何实时进程的优先级都高于普通进程的优先级。
普通进程用nice值得表示优先级,取值范围为[-20,19],默认为0。越低的nice值代表越高的优先级,越高优先级的普通进程有越高的执行时间。
实时优先级是可配置的,默认范围是[0,99]。与nice值相反,越高的实时优先级数值代表越高的优先级。
在Linux操作系统中,fork()函数用来创建一个新的进程,exec函数用来启动另外的程序以取代当前运行的进程。
在Linux中,创建进程的常见方法是使用fork函数从已经存在的进程(父进程)中创建一个新进程(子进程)。子进程是父进程的副本,子进程和父进程使用相同的代码包;子进程复制父进程的数据与堆栈空间,并继承父进程的用户代码等。由于子进程完全复制了父进程 ,因此父子进程会运行同一个程序。
int fork();
返回值意义如下:
大于等于0:正确返回
1)等于0,当前是子进程,从子进程返回进程ID值
2)大于0,表示当前进程是父进程,从父进程返回进程ID值
小 于 0 :错误返回,表示进程创建失败;原因:进程数达到上限/内存不足
子进程虽然继承了父类的一切数据,当子进程一旦开始运行,就会和父进程分开。子进程拥有自己的ID、资源、计时器等,与父进程之间不再共享数据。
- int getpid(); //取得当前进程的标识符
- int getppid(); //取得当前进程的父进程ID
- int getpgrp(); //取得当前进程的组标识符
- int getpgid(int pid); //将当前进程的组标识符改为当前进程的ID
execlp函数使用 - erictanghu - 博客园 (cnblogs.com)
execlp()会从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后将第二个以后的参数当做该文件的argv[0]、argv[1]……,最后一个参数必须用空指针(NULL)作结束。如果用常数0来表示一个空指针,则必须将它强制转换为一个字符指针,否则将它解释为整形参数,如果一个整形数的长度与char * 的长度不同,那么exec函数的实际参数就将出错。如果函数调用成功,进程自己的执行代码就会变成加载程序的代码,execlp()后边的代码也就不会执行了.
wait()和waitpid()的一些理解_wait(null)与wait(0)区别-CSDN博客
wait()系统调用挂起调用的执行进程,直到其子进程之一终止。
void exit(int status);
一个进程自我终止后,将释放所占资源并通知父进程可以删除它,此时它处于僵死状态。参数status是调用进程终止执行时传递给其父进程的值。
- 1.#include
- 2.#include
- 3.#include
- 4.#include
- 5.#include
- 6.#include
- 7.int main()
- 8.{
- 9. pid_t childpid; //放子进程的id
- 10. int retval; //设置的子进程的返回值
- 11. int status; //子进程向父进程提供的退出状态
- 12.
- 13. childpid=fork();//创建新进程
- 14. if(childpid>=0) //创建成功
- 15. {
- 16. if (childpid==0) //说明当前进程就是子进程
- 17. {
- 18. printf("CHILD: I am the child process! \n");
- 19. printf("CHILD: Here's my PID: %d\n", getpid());//getpid获得当前进程id
- 20. printf("CHILD: My parent's PID is: % d\n", getppid());//grtppid获得父进程id
- 21. printf("CHILD: The value of fork return is: % d\n", childpid);//fork的返回值
- 22. printf("CHILD: Sleep for 1 second...\n");
- 23. sleep(1);//让当前进程睡眠1秒
- 24.
- 25. printf("CHILD: Enter an exit value (0~255): ");
- 26. scanf("%d",&retval);//设置子进程返回值
- 27. printf("CHILD: Goodbye! \n");
- 28. exit(retval); //子进程退出,退出值为刚刚设置的
- 29. }
- 30. else //当前进程为父进程
- 31. {
- 32. printf("PARENT: I am the parent process! \n");
- 33. printf("PARENT: Here's my PID: %d\n", getpid());//当前进程id
- 34. printf("PARENT: The value of my child's PID is: %d\n", childpid);//子进程id
- 35.
- 36. printf("PARENT: I will now wait for my child to exit.\n");
- 37. wait(&status); //等待子进程运行结束,并保存其状态
- 38. printf("PARENT: Child's exit code is: %d\n", WEXITSTATUS(status));//输出子进程的返回值
- 39.
- 40. printf("PARENT: Goodbye! \n");
- 41. exit(0); //父进程退出
- 42. }
- 43. }
- 44. else //创建失败
- 45. {
- 46. perror("fork error!"); /*display error messsage*/
- 47. exit(0);
- 48. }
- 49.}
- 1.#include
- 2.#include
- 3.#include
- 4.#include
- 5.int main()
- 6.{
- 7. pid_t pid;
- 8. pid = fork();//创建新进程
- 9. if (pid < 0) { //进程创建失败
- 10. fprintf(stderr, "Fork Failed");//输出内容到文件
- 11. return 1;
- 12. }
- 13. else if (pid == 0) { //当前是子进程
- 14. execlp("/bin/ls","ls",NULL);
- 15. //execlp()会从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后将第二个以后的参数当做该文件的argv[0]、argv[1]……,最后一个参数必须用空指针(NULL)作结束。如果用常数0来表示一个空指针,则必须将它强制转换为一个字符指针,否则将它解释为整形参数,如果一个整形数的长度与char * 的长度不同,那么exec函数的实际参数就将出错。如果函数调用成功,进程自己的执行代码就会变成加载程序的代码,execlp()后边的代码也就不会执行了.
- 16. }
- 17. else { //父进程
- 18. wait (NULL);
- 19. //wait()系统调用挂起调用的执行进程,直到其子进程之一终止。
- 20. printf ("Child Complete");
- 21. }
- 22. return 0;
- 23.}
模拟调度算法
- 1.#include "stdio.h"
- 2.#include
- 3.#define getpch(type) (type*)malloc(sizeof(type))
- 4.
- 5.//模拟进程调度算法
- 6.struct pcb { /* 定义进程控制块PCB */
- 7. char name[10]; //进程名
- 8. char state; //进程状态:"W"-就绪态,"R"-运行态,F完成
- 9. int nice; //进程优先级
- 10. int ntime; //需要运行时间
- 11. int rtime; //已经运行的时间
- 12. struct pcb* link;
- 13.}*ready=NULL,*p;
- 14.typedef struct pcb PCB;
- 15.
- 16.char sort() /* 建立对进程进行优先级排列函数,优先数大者优先*/
- 17.{ //
- 18. PCB *first, *second;
- 19. int insert=0;
- 20. if((ready==NULL)||((p->nice)>(ready->nice)))/*优先级最大者,插入队首*/
- 21. {
- 22. p->link=ready;
- 23. ready=p;
- 24. }
- 25. else /* 进程比较优先级,插入适当的位置中*/
- 26. {
- 27. first=ready;
- 28. second=first->link;
- 29. while(second!=NULL)
- 30. {
- 31. if((p->nice)>(second->nice)) /*若插入进程比当前进程优先数大,*/
- 32. { /*插入到当前进程前面*/
- 33. p->link=second;
- 34. first->link=p;
- 35. second=NULL;
- 36. insert=1;
- 37. }
- 38. else /* 插入进程优先数最低,则插入到队尾*/
- 39. {
- 40. first=first->link;
- 41. second=second->link;
- 42. }
- 43. }
- 44. if(insert==0) first->link=p;
- 45. }
- 46.}
- 47.
- 48.char input() /* 建立进程控制块函数*/
- 49.{ //输入
- 50. int i,num;
- 51. printf("\n 请输入被调度的进程数目:");
- 52. scanf("%d",&num);
- 53. for(i=0;i
- 54. {
- 55. printf("\n 进程号No.%d:",i);
- 56. p=getpch(PCB);
- 57. printf("\n 输入进程名:");
- 58. scanf("%s",p->name);
- 59. printf(" 输入进程优先数:");
- 60. scanf("%d",&p->nice);
- 61. printf(" 输入进程运行时间:");
- 62. scanf("%d",&p->ntime);
- 63. printf("\n");
- 64. p->rtime=0;
- 65. p->state='W';
- 66. p->link=NULL;
- 67. sort(); /* 调用sort函数*/
- 68. }
- 69.}
- 70.
- 71.int space() //统计链表中结点个数
- 72.{
- 73. int l=0; PCB* pr=ready;
- 74. while(pr!=NULL)
- 75. {
- 76. l++;
- 77. pr=pr->link;
- 78. }
- 79. return(l);
- 80.}
- 81.
- 82.char disp(PCB * pr) /*建立进程显示函数,用于显示当前进程*/
- 83.{
- 84. printf("\n qname \t state \t nice \tndtime\truntime \n");
- 85. printf("%s\t",pr->name);
- 86. printf("%c\t",pr->state);
- 87. printf("%d\t",pr->nice);
- 88. printf("%d\t",pr->ntime);
- 89. printf("%d\t",pr->rtime);
- 90. printf("\n");
- 91.}
- 92.
- 93.char check() /* 建立进程查看函数 */
- 94.{
- 95. PCB* pr;
- 96. printf("\n **** 当前正在运行的进程是:%s",p->name); /*显示当前运行进程*/
- 97. disp(p); //显示进程信息
- 98. pr=ready;
- 99. if (pr!=NULL)
- 100. printf("\n ****当前就绪队列状态为:"); /*显示就绪队列状态*/
- 101. else
- 102. printf("\n ****当前就绪队列状态为: 空\n"); /*显示就绪队列状态为空*/
- 103. while(pr!=NULL)
- 104. {
- 105. disp(pr);
- 106. pr=pr->link;
- 107. }
- 108.}
- 109.
- 110.char destroy() /*建立进程撤消函数(进程运行结束,撤消进程)*/
- 111.{
- 112. printf(" 进程 [%s] 已完成.\n",p->name);
- 113. free(p);
- 114.}
- 115.
- 116.char running() /* 建立进程就绪函数(进程运行时间到,置就绪状态*/
- 117.{
- 118. (p->rtime)++; //运行时间增加
- 119. if(p->rtime==p->ntime) //达到要求的时间
- 120. destroy(); //完成进程并释放
- 121. else
- 122. {
- 123. (p->nice)--; //优先级减少
- 124. p->state='W'; //改状态
- 125. sort(); //按优先级重新排序
- 126. }
- 127.}
- 128.
- 129.int main() /*主函数*/
- 130.{
- 131. int len,h=0;
- 132. char ch;
- 133. input();
- 134. len=space(); //链表长度
- 135. while((len!=0)&&(ready!=NULL)) //只要队列不空
- 136. {
- 137. ch=getchar();
- 138. h++;
- 139. printf("\n The execute number:%d \n",h); //输出当前正在处理的进程号
- 140. p=ready; //换到下一个结点
- 141. ready=p->link; //记录下一个结点
- 142. p->link=NULL; //删除连接
- 143. p->state='R'; //更新状态
- 144. check(); //展示进程数
- 145. running(); //运行进程
- 146. printf("\n按任一键继续......");
- 147. ch=getchar();
- 148. }
- 149. printf("\n\n 所有进程已经运行完成!\n");
- 150. ch=getchar();
- 151.}