Linux下利用文件IO函数完成多进程复制图片,父进程复制前一半,子进程复制后一半
本小节内容参考了这篇文章: 进程的状态转换
引起进程挂起的原因是多样的,主要有:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
显示进程占计算机的资源百分比。
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
功能:显示当前进程的家族关系。
例如:让a.out进入死循环防止程序结束后可以输入下面的指令查看
ps -ajx|grep a.out
功能:根据进程名字获取PID号;
pidof a.out 查看所有进程名为a.out的,进程的id号
7412 7390
功能:实时显示进程状态
输入q退出
top -d 刷新秒数
功能:显示进程关系树
kill -9 pid 根据pid号杀死进程
killall -9 进程名字 根据进程名字杀死进程
D 无法被中断的阻塞状态
R 运行状态
S 可以被终端的阻塞状态(sleep)
T 被挂起的状态
t 被追踪的状态(gdb调试工具)
X 死亡状态,死亡是一瞬间的事情,永远不会被捕获到
Z 僵尸进程,当进程退出后,父进程没有给它收尸。
For BSD formats and when the stat keyword is used, additional characters may be displayed:
< 高优先级
N 低优先级
L 有些页被锁进内存
s 会话组组长,代表有子进程的进程
l 多线程
+ 运行在前端
功能:创建一个子进程;
原型:
#include
#include
pid_t fork(void);
参数:
返回值:
成功, >0 在父进程中返回新建的子进程的pid号
=0 在子进程中返回0;
失败,在父进程中返回-1,更新errno.且此时没有子进程被创建。
功能:
获取当前进程的pid号/获取父进程的pid号
原型:
#include
#include
pid_t getpid(void);
pid_t getppid(void);
返回值:
永远成功,返回pid号(当前进程的id号)、ppid号(当前进程的父进程的id号,parent id)
功能:
当运行到该函数的时候会退出进程,且**不会刷新缓冲区**,**直接销毁缓冲区**。
原型:
#include
void _exit(int status);
参数:
int status:传递子进程的退出状态值给父进程。父进程可以通过wait/waitpid函数接收。
可以传入任意整型数
功能:
当运行到该函数的时候会退出进程,但是 **会刷新缓冲区**
原型:
#include
void exit(int status);
参数:
int status:传递子进程的退出状态值给父进程。父进程可以通过wait/waitpid函数接收。
可以传入任意整型;
注意: 若只退出子进程,而其父进程没有给子进程收尸的时候,子进程的资源没有被回收,此时子进程会变成僵尸进程
功能:
阻塞函数,阻塞等待任意一个子进程退出,解除阻塞;
接收子进程的退出状态值。(exit _exit main函数调用return传递出来的值);
回收任意一个子进程的资源(收尸,防止尸变--占用资源);
原型:
#include
#include
pid_t wait(int *wstatus);
参数:
int *wstatus:接收子进程传递回来的退出状态值,若不想接收,则填NULL;
返回值:
>0, 成功返回退出的子进程的PID号;
=-1,函数运行失败,更新errno;
#define __WEXITSTATUS(status) (((status) & 0xff00) >> 8)
使用方法:
WEXITSTATUS(wstatus)
WIFEXITED(wstatus):判断子进程是否正常退出
waitpid
功能:
阻塞函数,阻塞等待指定的一个子进程退出,解除阻塞;
接收该子进程的退出状态值。(exit _exit main函数调用return传递出来的值);
回收该一个子进程的资源(收尸);
原型:
#include
#include
pid_t waitpid(pid_t pid, int *wstatus, int options);
参数:
pid_t pid:
//< -1 阻塞等待指定进程组下的任意一个子进程退出。进程组id = -pid参数;
-1 阻塞等待当前进程下的任意一个子进程退出。此时功能等价于wait函数
//0 阻塞等待当前进程组下的任意一个子进程退出。
> 0 阻塞等待子进程,子进程的id号 == pid参数;
int *wstatus:接收子进程传递回来的退出状态值,若不想接收,则填NULL;
int options:
0:阻塞方式,若指定的子进程没有退出,则该函数阻塞。直到指定的子进程退出后,解除阻塞.
WNOHANG:非阻塞方式,若指定的子进程没有退出,则该函数也不阻塞,且没有回收到资源。
返回值:
成功,>0, 成功回收到的子进程的pid号;
=0, 函数运行成功,但是指定的子进程未退出,此时没有收到子进程的资源。
失败,(例如进程下没有子进程的时候)返回-1,更新errno;
通过一下实验得到结果,注意:
1. 若没有子进程,则函数运行失败。
2. 函数只能回收子进程的资源,无法跨辈回收,
例如爷收孙,子收父,兄弟进程相互回收,均无法成立。
代码示例 :
#include
#include
#include
int main(int argc, const char *argv[])
{
//创建子进程,退出父进程,子进程不退出
pid_t cpid = fork();
if(0 == cpid)
{
while(1)
{
printf("this is child %d %d\n", getppid(), getpid());
sleep(1);
}
}
return 0;
}
代码示例:
#include
#include
#include
int main(int argc, const char *argv[])
{
//子进程退出,父进程不退出,且父进程没有回收退出的子进程的资源。
pid_t cpid = fork();
if(cpid > 0)
{
while(1)
{
printf("this is parent %d %d\n", getpid(), cpid);
sleep(1);
}
}
return 0;
}
功能:
创建一个新的进程组和会话组,成为该进程组和会话组组长;
原型:
#include
#include
pid_t setsid(void);
功能:修改运行目录;
#include
int chdir(const char *path);
如:
chdir("/");
代码示例:
#include
int main(int argc, const char *argv[])
{
//创建孤儿进程:所有的任务放在子进程中运行,形式上脱离终端控制
pid_t cpid = fork();
if(0 == cpid)
{
//创建新的会话:使子进程完全独立出来,脱离其他亲缘关系进程的控制
pid_t pid = setsid();
// printf("pid=%d\n", pid);
//修改运行目录为不可卸载的文件系统:例如根目录,一般约定俗称,若有工作日志要输出,则运行在/tmp目录下。
chdir("/");
//重设文件权限掩码:;一般清0(umask(0))
umask(0);
//关闭所有文件描述符:子进程的文件描述符继承父进程的,包括了0 1 2.
for(int i=0; i<getdtablesize(); i++)
close(i);
while(1)
{
//周期性执行的功能代码
sleep(1);
}
}
return 0;
}