Linux系统编程笔记(04)

gdb调试:
	gdb调试的时候,只能跟踪一个进程,在fork()之前,通过指令设置gdb跟踪父进程还是跟踪子进程,默认跟踪父进程
	设置父进程调试路径:(gdb)set follow-fork-mode parent (默认)
	设置子进程调试路径:(gdb)set follow-fork-mode child  //fork之后跟踪子进程

exec函数族:
	fork()创建子进程后执行的是和父进程相同的程序(但有可能是不同代码分支)
	子进程往往要调用一种exec()函数,以指定子进程去执行另一个程序
	当进程调用exec()时,该进程的用户空间代码和数据,完全被新程序取代
	从新程序开始执行,调用exec()并不创建新进程,所以进程id并不改变,换核不换壳

	int execlp(const char *file, const char *arg, ...);	//借助PATH环境变量,寻找待执行程序
	功能:使进程执行某一程序。成功无返回值,失败返回 -11: 要执行程序的名,当PATH中所有目录搜索后都没有参1,则出错返回
		参2: argv0 注意,此函数从argv0开始算,所以参2好多时候都和参1一样
		参3: argv1
		...: argvN
		哨兵:NULL,代表参数的结束,放在所有参数的最后
	该函数经常用来执行系统程序,如ls、data、cp、cat等
	execlp("ls", "ls", "-l", "-h", NULL);

	int execl(const char *path, const char *arg, ...); //自己指定待执行程序路径1:要执行程序的路径
	一般用来执行自己的可执行程序
	execl("./a.out", "./a.out", "NULL");
	
	int execvp();

ps ajx --> pid ppid gid sid 

孤儿进程:
	父进程先于子进程死,子进程沦为“孤儿进程”,会被 init 进程领养,领养的目的是回收子进程。
僵尸进程:
	子进程死,父进程尚未对子进程进行回收,子进程用户空间中的内容都没了,但子进程残留的资源(PCB进程控制块)存放于内核中,为“僵尸进程”。
	kill对其无效。

    一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB进程控制块还保留着,内核在其中保存了一些信息:如果是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除掉这个进程。我们知道一个进程的退出状态可以在Shell中用特殊变量S?查看,因为Shell是它的父进程,当它终止时Shell调用wait或waitpid得到它的退出状态同时彻底清除掉这个程。

wait函数:回收子进程退出资源, 阻塞回收任意一个。
	pid_t wait(int *status)
	参数:(out)回收进程的状态。
	返回值:成功: 回收进程的pid
			失败: -1, errno
	函数作用1:阻塞等待子进程退出(父进程啥也不干,等子进程死)
	函数作用2:清理子进程残留在内核的PCB资源
	函数作用3:通过传出参数,得到子进程结束状态

waitpid函数:指定某一个进程进行回收。可以设置非阻塞。			waitpid(-1, &status, 0) == wait(&status);
	pid_t waitpid(pid_t pid, int *status, int options)1:指定回收某一个子进程pid
			>0:待回收的子进程pid
			-1:任意子进程
			 0:同组的子进程
	参2:(传出)回收进程的状态。
	参3:WNOHANG 指定回收方式为,非阻塞,父进程就不傻等了。
	返回值:
		>0:表示成功回收的子进程 pid
		 0:函数调用时,参3指定了WNOHANG,并且 没有子进程结束。
		-1:失败。errno
总结:wait、waitpid	一次调用,只回收一个子进程。想回收多个。用while循环 

	借助宏函数来判断进程终止的具体原因
	获取子进程正常终止值:以下这些是宏函数,把存放被回收进程的状态的变量status传入
		WIFEXITED(status) 如果为真,说明进程正常结束,则调用 WEXITSTATUS(status),得到 子进程 的退出值。
	获取导致子进程异常终止信号:
		WIFSIGNALED(status)如果为真,说明进程异常结束,则调用 WTERMSIG(status),得到 导致子进程异常终止的信号编号。
===========================

在这里插入图片描述

不同进程间的内核空间(3G-4G)可以互相连通,进程间通信,说白了,就是内核空间中的一块缓冲区,这个缓冲区一般大小是4096
进程间通信的常用方式,特征:
	管道:简单
	信号:开销小,速度快,但传输数据的种类和数据量 都有限,
	mmap映射(共享内存映射):非血缘关系进程间
	socket(本地套接字):稳定,实现比较复杂

管道:
	只能在 有亲缘关系的 进程之间通信。例如父子,兄弟,叔侄
	实现原理:内核借助环形队列机制,使用内核缓冲区实现。
	特质:
	1.伪文件
		Linux有7种文件类型:普通文件、目录、软链接、字符设备、块设备、管道、套接字。
		其中,普通文件、目录、软链接是真正占用磁盘空间的,其他4个都是伪文件,都不占用磁盘空间,只占用内存,占用内存的一块缓冲区。
	2.管道中的数据只能一次读取。
	3.数据在管道中,只能单向流动。
	原理:
	内核使用环形队列机制,借助内核缓冲区(4k)实现。
	局限性:
	1.自己写,不能自己读。
	2.数据不可以反复读。
	3.半双工通信。
	4.血缘关系进程间可用。
	
pipe函数:	创建,并打开管道。
	int pipe(int fd[2]);
	参数:fd[0]: 读端。
		 fd[1]: 写端。
	返回值: 成功: 0  失败: -1 errno

管道的读写行为:
	读管道:
		1. 管道有数据,read返回实际读到的字节数。
		2. 管道无数据:	
		   1)无写端,read返回0 (类似读到文件尾)
		   2)有写端,read阻塞等待。
	写管道:
		1. 无读端, 异常终止。 (SIGPIPE信号导致的)
		2. 有读端:	
		   1) 管道已满, 阻塞等待
		   2) 管道未满, 返回写出的字节个数。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值