操作系统环境编程(2)

fork创建子进程后执行的是和父进程相同的程序,子进程往往要调用一种exec函数以执行另一个程序。
其中有六种以exec开头的函数,统称exec函数:常用两种
execlp      :p->path :该变量通常来调用系统程序。如:ls、cp、cat

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

int main()
{
    pid_t pid;
    pid = fork();
    if(pid == -1)
    {
        perror("fork error");
        exit(1);
    }
    else if(pid > 0)
    {
        sleep(1);
        printf("parent\n");
    }
    else
    {
        execlp("ls", "ls", "-l", "-a", "-h", NULL);
    }
    return 0;
}

execl函数:加载一个进程,通过 路径+程序名 来加载
 

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

int main()
{
    pid_t pid;
    pid = fork();
    if(pid == -1)
    {
        perror("fork error");
        exit(1);
    }
    else if(pid > 0)
    {
        sleep(1);
        printf("parent\n");
    }
    else
    {
        execlp("/bin/ls", "ls", "-l", "-a", "-h", NULL); //可加载自定义程序
    }
    return 0;
}

回收子进程

  • 孤儿进程:父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为init进程,称init进程领养孤儿过程。
  • 僵尸进程:子进程终止,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸进程。

注:僵尸进程不能使用kill命令清除掉。因为kill命令只是用来终止进程的,而僵尸进程已经终止。

wait函数
该函数有三个功能:

  •     阻塞等待子进程退出(子进程没死)
  •     回收子进程残留资源
  •     获取子进程结束状态(退出原因)

pid_t wait(int* status); 成功:清理掉的子进程ID 失败:-1(没有子进程)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void)
{
    pid_t pid, wpid;
    pid = fork();
    
    if(pid == 0)
    {
        printf("---child, my parent = %d, going to sleep 10s\n", getppid());
        sleep(10);
        printf("-----child die-----\n"):
    }
    else if(pid > 0)
    {
        wpid = wait(NULL);            //回收
        if(wpid == -1)
        {
            perror("wait error");
            exit(1);
        }
        while(1)
        {
            printf("I am parent, pid = %d, myson = %d\n", getpid(), pid);
        }
    }
    else{
        perror("fork");
        return 1;
    }
    
    return 0;
}

可使用wait函数传出参数status来保存进程的退出状态。借助宏函数来进一步判断进程终止的原因。宏函数可分为如下三组:
1.WIFEXITED(status) 为非0 -> 进程正常结束
  WEXITSTATUS(status) 如果宏为真,使用此宏->获得进程退出状态(exit)的函数
2.WIFSIGNALED(status) 为非0 -> 进程异常终止
  WTERMSIG(status)    如果宏为真,使用此宏->获取是进程终止的那个信号的编号
3.不常用了解即可

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void)
{
    pid_t pid, wpid;
    int status;
    pid = fork();
    
    if(pid == 0)
    {
        printf("---child, my parent = %d, going to sleep 10s\n", getppid());
        sleep(3);
        printf("-----child die-----\n");
        exit(76);
    }
    else if(pid > 0)
    {
        wpid = wait(&status);            //回收
        if(wpid == -1)
        {
            perror("wait error");
            exit(1);
        }
        if(WIFEXITED(status))
        {
            printf("child exit with %d\n", WEXITSTATUS(status));
        }
        if(WIFSIGNALED(status))
        {
            printf("child kelled by %d\n", WEXITSTATUS(status));
        }
        
        while(1)
        {
            printf("I am parent, pid = %d, myson = %d\n", getpid(), pid);
            sleep(1);
        }
    }
    else{
        perror("fork");
        return 1;
    }
    
    return 0;
}

waitpid函数
作用同wait,但可以指定pid进程清理,可以不阻塞。
pid_t wiatpid(pid_t pid, int* status, in options); //参数 回收id 回收状态 设置非阻塞状态

IPC方法 InterProcess Communication
7种文件类型
占用磁盘存储
    - 文件
    d 目录
    l 符号链接
:伪文件(不占用磁盘存储)
    s 套接字
    b 块设备
    c 字符设备
    p 管道
    

现常用的进程间通信的方式有:管道、信号、共享映射区、本地套接字
管道:
    pipe
    管道一般读写行为
fifo:(有名管道)
    用于非血缘关系进程间通信
共享内存:
    mmap
    函数的参数使用注意事项
    用于非血缘关系进程间通信
    
管道的概念:
    管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。
    特性:
        本质是一个伪文件
        由两个文件描述符引用,一个表示端,一个标识写端
        规定数据从管道写端流入管道,从读端流出。
    管道的原理:管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。
    管道的局限性:
        读端只读不写,写端只写不读
        数据一旦被读走,便不在管道中存在,不可反复读取。
        由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。
        只能在有公共祖先的进程间使用管道。
pipe函数创建管道
int pipe(int pipefd[2]);     成功:0; 失败:-1
行数调用成功返回r/w两个文件描述符。无需open,需要手动close。规定:fd[0]->r; fd[1]->w。向管道文件读写数据其实是在读写内核缓冲区。

 

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

int main()
{
	int fd[2];
	pid_t pid;
	
	int ret = pipe(fd);
	if(ret == -1)
	{
		perror("pipe error:");
		exit(1);
	}
	pid = fork();
	if(pid == -1)
	{
		perror("pipe error:");
		exit(1);
	}
	else if(pid == 0) //子 读数据
	{
		close(fd[1]);
		char buf[1024];
		ret = read(fd[0], buf, sizeof(buf));
		if(ret == 0)
		{
			printf("----\n");
		}
		write(STDOUT_FILENO, buf, ret);
	}
	else			  //父 写
	{
		close(fd[0]);
		write(fd[1], "hello pipe\n", strlen("hello pipe\n"));
	}
	
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值