头歌Linux——Linux系统的进程控制 练习二 2023-04-06

第1关:进程创建

任务描述

fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程。那么,进程中的变量父进程和子进程是否都能使用并修改呢?

围绕问题的提出,我们尝试在父子进程中都修改同一个文件中的内容,最终将文件内容输出,便可知晓答案。

下面我们通过学习相关知识并编写代码来测试你的猜想是否正确。

相关知识

Linux 进程中的几个状态:

  • R 运行状态 (runing),并不意味着进程一定在运行中,也可以在运行队列里

  • S 睡眠状态 (sleeping),进程在等待事件完成(浅度睡眠,可以被唤醒)

  • D 磁盘睡眠状态 (Disk sleep),不可中断睡眠(深度睡眠,不可以被唤醒,通常在磁盘写入时发生)

  • T 停止状态 (stopped),可以通过发送 SIGSTOP 信号给进程来停止进程,可以发送 SIGCONT 信号让进程继续运行

  • Z 僵尸状态 (zombie),子进程退出,父进程还在运行,但是父进程没有读到子进程的退出状态,子进程进入僵尸状态

为了完成本关任务,你需要掌握:1. 如何创建进程;2.fork()函数的执行步骤。

进程的创建

在使用创建进程函数前,我们需要先导入unistd.h库。

创建进程的函数原型是:pid_t fork(void);

例如:

 
  1. pid_t pid = fork();

pid_t是一个整数类型,即fork()函数会返回新进程的 ID 号(0~32768的整数)。fork函数在父进程中返回子进程的pid,在子进程中返回0

注意在子进程中返回的0,并不是子进程的pid,子进程的pid在父进程的返回值中保存。而子进程的返回值是为了标识它是子进程,用来区分父子进程的。

父子进程的注意事项:

  1. 新进程是当前进程的子进程

  2. 父进程和子进程 ①父进程:fork()的调用者; ②子进程:新建的进程。

  3. 子进程是父进程的复制(相同的代码,相同的数据,相同的堆栈),除了 ID 号和时间信息外,两者完全相同。

  4. 子进程和父进程可以并发运行。

fork()函数的执行步骤

由于子进程是父进程的复制,所以子进程中也会有创建子进程的语句,如果不加以限制,就会形成递归创建,但实际上并不是这样的。

实际流程是:父进程创建了子进程后,子进程中“创建进程”语句不再执行,并发运行其他语句。

在 Linux 的源码中我们可以找到fork函数:

 
  1. ...
  2. copy_files(clone_flags,p); //克隆文件
  3. copy_fs(clone_flags,p); //克隆文件系统
  4. copy_mm(clone_flags,p); //克隆内存信息
  5. ...

我们可以看到有三条语句,用于拷贝进程的所有信息,这也解释了为什么说子进程是父进程的复制。

编程要求

通过提示,在右侧编辑器中补充代码,完成在指定文件中添加内容,具体要求如下:

  1. 创建进程;
  2. 父进程向文件中添加hello 和 world!
  3. 子进程向文件中添加hello 和 welcome!
  4. 只需修改文件内容即可,平台将为你输出文件内容。

提示:fork()函数的返回值为0时则为子进程。

测试说明

平台会对你编写的代码进行测试:

预期输出: hello world! hello welcome!


开始你的任务吧,祝你成功!

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

//ÇëÔÚ´Ë´¦Ìí¼Óµ¼ÈëÏàÓ¦¿âº¯Êý´úÂë
int main(){
    
	FILE *fp=fopen("test.txt","w+");
    int pid;
    	//pid±íʾforkº¯ÊýµÄ·µ»ØÖµ
	/**********  Begin  **********/

	char *hello="hello ";
    char *world="world!\n";
    char *welcome="welcome!\n";
    fwrite(hello,strlen(hello),1,fp);
    if((pid=fork())==0)
    {    //子进程
        fwrite(welcome,strlen(welcome),1,fp);
    }else
    {    //父进程
        fwrite(world,strlen(world),1,fp);
    }
	/**********  End  **********/
    fclose(fp);
	return 0;
	
}

第2关:进程加载

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h> 		
         //ÇëÔÚ´Ë´¦Ìí¼Óµ¼ÈëÏàÓ¦¿âº¯Êý´úÂë
 		

int main(){
	/**********  Begin  **********/
    //¸¸½ø³ÌÊä³ö
      printf("entering main process---\n");  
    //×Ó½ø³ÌÖ´ÐÐhello.cÎļþ
      if(fork()==0){
        int ret=execl("./hello","hello",NULL);
        if(ret == -1){
            perror("error,failed to execute hello programe\n");
            exit(1);
        }
    }


	/**********  End  **********/
    return 0;
}

第3关:进程等待与退出

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
					//请在此处添加导入相应库函数代码

int main()
{
	int p1, p2; //进程ID
  	/**********  Begin  **********/
    p1 = fork();
    if(p1==0){        //第一个子进程
        execl("/bin/echo","echo","I am first process!",NULL);
        exit(1);
    }else{
        wait(NULL);    //用于进程同步,wait函数的作用是:父进程在此处暂停运行,等待一个子进程结束后,再从此处继续向下运行
    }
    p2=fork();
    if(p2==0){        //第二个子进程
        execl("/bin/echo","echo","I am second process!",NULL);
        exit(1);
    }else{
        wait(NULL);
    }
    printf("I am father process!\n");
	/**********  End  **********/
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张謹礧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值