进程调度的认识和小结

1.资源继承
    fork()函数,分叉函数
    调用fork()函数,可以生成当前程序的副本(子进程)。 子进程有复制来自父进程的堆栈段和数据空间(包括流缓冲区)。之后由系统调度算法决定执行哪一个进程先执行(包括显示中终端命令行的进程也会参与系统资源的争夺)。
    如在下面的两个程序中,就因为一个'\n',而使两个程序出现的结果,有别于以往的认识。
程序一:

#include<unistd.h>
#include<stdio.h>
#include <sys/types.h>
int main()
{
   printf("最初该进程的id为:%d\n",getpid());
   printf("Before fork...");
   pid_t pid = fork();
   if(pid == 0)
   {
      printf("此时调用子进程,id为:%d, 该子进程的父进程id为:%d\n",getpid(),getppid());
   }
   else
   {
      printf("此时调用父进程,id为:%d, 子进程的id为:%d\n",getpid(),pid);
   }
   return 0;
}

运行结果:


不知道你们注意到没有,子进程它的父进程竟然与最开始的进程的id不一样,原因就是因为显示终端命令的进程也参与了系统资源的竞争,此时子进程没能竞争上,所以他(3754进程)的父进程就变成了2170(显示终端命令的进程)。

程序二:

#include<unistd.h>
#include<stdio.h>
#include <sys/types.h>
int main()
{
   printf("最初该进程的id为:%d\n",getpid());
   printf("Before fork...\n");
   pid_t pid = fork();
   if(pid == 0)
   {
      printf("此时调用子进程,id为:%d, 该子进程的父进程id为:%d\n",getpid(),getppid());
   }
   else
   {
      printf("此时调用父进程,id为:%d, 子进程的id为:%d\n",getpid(),pid);
   }
   return 0;
}

运行结果:

可以看到在程序二中,Before fork... 只出现了一次。这是因为printf的输出机制,当printf中没有'\n'时,只是先将内容放入标准输出队列缓冲区中,所以在程序一,子进程也拥有了(继承但不是共享)父进程缓冲区的内容。而当遇到了'\n', 此时会刷新标准输出队列(stdout),因此,在程序二中,也就只有一个Before fork...

 

2.进程并发执行和并发控制

   (1)并发执行

程序三:

#include<unistd.h>
#include<stdio.h>
int main()
{
   int p1,p2;
   while ((p1 = fork()) == -1);  //创建子进程p1
   if (p1 == 0)  //执行子进程p1
      printf("BBB\t");
   else
   {
      while((p2 = fork()) == -1); //创建子进程p2
      if (p2 == 0) //执行子进程2
         printf("CCC\t");
      else
         printf("AAA\t");  //父进程执行
   }                     
    return 0;
}

运行结果:

 

三个进程随机调度,理论上还有其他的结果BBB AAA CCC等。

(2)并发控制

lockf函数

int lockf(int fd, int cmd, off_t len);
/*
fd代表文件描述符(0为写入(stdin),1为输出(stdout))
cmd操作控制值(0~3),0代表开锁,1代表加锁
len代表要锁定或解锁的连续字节数。0表示从调用lockf()后开始锁定
*/

程序四:

#include<unistd.h>
#include<stdio.h>
int main()
{
   int p1, p2, i;
   while ((p1 = fork()) == -1);//创建子进程p1
      if (p1 == 0)//执行子进程p1,输出100个son
         for (i = 0; i < 100; i++) printf("son%d\n",i);
      else
      {
         while ((p2 = fork()) == -1);//创建子进程p2
            if (p2 == 0)//执行子进程p2,输出100个daughter
               for (i = 0; i < 100; i++) printf("daughter%d\n",i);
            else
               for (i = 0; i < 1000; i++) //父进程执行,输出1000个children
                  printf("children%d\n",i);
      }
   return 0;
}

运行结果:

 

  

因为结果太长,这里只截取了一部分,为了使效果更加明显,输出了1000个children单词和100个son和100个daughter单词。可以看到程序四和程序三只是输出的次数和内容不同,总体框架是一样的,但在程序四中,进程之间的调度会给人一种很乱的感觉。某个进程的单词插到了另外进程的单词中了。这是因为在调用父进程输出children时, 此时使用的是外设(打印到屏幕上),父进程会进入阻塞状态,cpu进程数少一个,就要调度其他的进程,比如调用了son这个进程,那么它也要使用输出的外设,而此时这个外设(打印到屏幕上)我们并没有给它加锁,因此它会去和children竞争这个设备,同理daughter也一样,结果就是正如我们所看到的一样。在程序五中,加上了锁,此时其他进程,只能等待当前外设的解锁。

程序五

#include<unistd.h>
#include<stdio.h>
int main()
{
   int p1, p2, i;
   while ((p1 = fork()) == -1); //创建子进程p1
   if (p1 == 0)//执行子进程p1,输出20个son
   {
      lockf(1,1,0);
      for (i = 0; i < 20; i++) printf("son%d\n",i);
      lockf(1,0,0);
   }
   else
   {
      while ((p2 = fork()) == -1); //创建子进程p2
      if (p2 == 0)//执行子进程p2,输出100个daughter
      {
         lockf(1,1,0);
         for (i = 0; i < 20; i++) printf("daughter%d\n",i);
         lockf(1,0,0);
      }
      else{
         lockf(1,1,0);
         for (i = 0; i < 20; i++)  //父进程执行,输出1000个children
            printf("children%d\n",i);
         lockf(1,0,0);
      }
   }
   return 0;
}

运行结果:

  

可以看到单词不会乱串了。

最后,补充一点exit(0),只是造成该进程终止,不一定是整个程序的结束(如果这个程序只有一个进程的话)。

 

附上一点实用命令:

1. gcc code.c -o code #编译链接并形成可执行文件code

2. vim 下代码格式化(代码格式化参考:https://blog.csdn.net/qachenzude/article/details/25511875):

(1)gg到第一行

(2)shift+v   转到可视模式

(3)shift+g  全选

(4) 按下 =

3. linux shell 重复执行n次同一命令: seq n|xargs -i cmd (效果:执行cmd命令n次, 顺序执行)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值