目录
1、fork
(1)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
int main()
{
pid_t pid;
pid = fork();
if(pid == 0){
printf("child: pid = %d\n", getpid());
//exit(88);
return 99; //进程推出时的返回值
}
else if(pid > 0){
printf("father: pid = %d\n", getpid());
//wait(NULL); //不关心子进程状态
int status;
waitpid(-1, &status, 0);
if(WIFEXITED(status)) //子进程正常返回
printf("child %d exit normally with %d\n", pid, WEXITSTATUS(status));
//子进程推出时的返回值
else //子进程非正常返回
printf("child %d exit abnormally\n", pid);
}
return 0;
}
./test
father: pid = 6890
child: pid = 6891
child 6891 exit normally with 99
(2)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
int main()
{
pid_t pid;
pid = fork();
if(pid == 0){
printf("child: pid = %d\n", getpid());
sleep(10);
printf("child %d exit\n",getpid());
//exit(88);
return 99; //进程推出时的返回值
}
else if(pid > 0){
printf("father: pid = %d\n", getpid());
int status;
waitpid(-1, &status, 0);
if(WIFEXITED(status)) //子进程正常返回
printf("child %d exit normally with %d\n", pid, WEXITSTATUS(status));
//子进程推出时的返回值
if(WIFSIGNALED(status)) //子进程非正常返回,收到信号
printf("child %d exit by signal %d\n", pid, WTERMSIG(status));
//kill -9 child_pid,9号信号
}
return 0;
}
./test
father: pid = 7251
child: pid = 7252
child 7252 exit by signal 9
// kill -9 7252 //开另一个终端,执行
kill -l // 查看信号
2、execlp、execl
exec 族函数执行成功不返回,直接在子进程中加载要执行的新程序。执行失败,则返回-1,执行子进程调用该函数之后的代码。
借用了进程的壳子,加载和执行了新的程序。pid 并没有改变,并且继承了打开的文件描述符。
WIFEXITED(status); // 宏函数,判断子进程是否正常退出。
WEXITESTATUS(status); // 正常终止的退出值。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
int main()
{
pid_t pid;
pid = fork();
if(pid == 0){
printf("child: pid = %d, father: %d\n", getpid(), getppid());
//execlp("ls", "ls", "-l", NULL); //执行其他程序,p代表环境变量。执行成功不返回,执行失败才返回。
//execl("./test", "test", NULL); //不加环境变量,直接某路径下的程序
char *argv[] = {"ls", "-l", NULL};
execvp("ls", argv);
}
else if(pid > 0){
printf("father: pid = %d\n", getpid());
int status;
waitpid(-1, &status, 0); //-1等所有进程,status结束状态,0阻塞等待。只要等到一个,则返回。
//wait(&status); //
if(WIFEXITED(status)) //子进程正常返回。宏函数
printf("child %d exit normally\n", pid);
else //子进程非正常返回
printf("child %d exit abnormally: %d\n", pid, WEXITSTATUS(status));
}
return 0;
}
3、执行 ps aux
ps ajx // 可以打印 pid,ppid
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <fcntl.h>
int main()
{
//打开一个文件,保存 ps aux 的输出结果
int fd;
fd = open("ps.out", O_WRONLY|O_CREAT|O_TRUNC, 0644);
if(fd<0){
perror("open ps.out error");
exit(1);
}
//修改标准输出
dup2(fd, STDOUT_FILENO);
//执行命令 ps -aux
execlp("ps", "ps", "aux", NULL); //不返回
perror("execlp error");
//close(fd); // 无法关闭文件,只能在成员运行结束后隐式关闭
return 0;
}
4、孤儿进程、僵尸进程
孤儿进程:父进程先死亡,子进程的父进程变为 init 进程,这样的子进程成为孤儿进程。
僵尸进程:子进程死亡,但是内核中还保留着子进程的pcb没有倍回收,其中记录了子进程的死亡原因。kill 命令无法清除僵尸进程。
(1)如何回收僵尸进程
由父进程调用 wait 回收;
设置 signal(SIGCHLD, SIG_IGN); // 父进程忽略子进程的回收信号,由内核负责回收
父进程正常终止,或者,杀死父进程,僵尸子进程变为孤儿进程,并立即由 init 进程回收。
(2)
5、s_mod 文件权限、umask 文件权限创建屏蔽字
文件的9种权限
S_IRUSR
S_IWUSR
S_IXUSR
S_IRGRP
S_IWGRP
S_IXGRP
S_IROTH
S_IWOTH
S_IXOTH
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#define RWRWRW S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH
#define RWRW S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH
int main()
{
pid_t pid, wpid;
signal(SIGCHLD, SIG_IGN); // 忽略,由内核代为回收
pid = fork();
if(pid == 0){
printf("child pid : %d\n", getpid());
sleep(1);
printf("child exit\n");
}
else if(pid > 0){
printf("father: pid = %d\n", getpid());
umask(0); // 不屏蔽任何权限
if(creat("file_1", RWRWRW) < 0){
printf("create file_1 error\n");
exit(1);
}
umask(RWRW); // 屏蔽:用户组读写、其他读写权限,再创建的文件将不具有这些权限
if(creat("file_2", RWRWRW) < 0){
printf("create file_2 error\n");
exit(1);
}
}
else {
printf("fork error\n");
}
return 0;
}
ls -l
-rw-rw-rw-. 1 name name 0 9月 25 17:00 file_1
-rw-------. 1 name name 0 9月 25 17:00 file_2 // 文件2某些权限并没有获得
6、vfork
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <sys/types.h>
int main()
{
pid_t pid;
int cnt = 0;
//signal(SIGCHLD, SIG_IGN);
pid = vfork(); // vfork
if(pid == 0){
printf("child pid : %d\n\n", getpid());
cnt++; // 子进程对 cnt 进行修改
//exit(1);
_exit(1); // vfork必须退出,标志子进程推出,父进程之后运行。否则未知错误
}
else if(pid > 0){
printf("father: pid = %d\n", getpid());
printf("cnt = %d\n", cnt); // 父进程打印 cnt
}
else {
printf("fork error\n");
}
return 0;
}
./test7_vfork
child pid : 16774
father: pid = 16773
cnt = 1
7、子进程等待父进程,父先终止
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <sys/types.h>
int main()
{
pid_t pid;
signal(SIGCHLD, SIG_IGN);
pid = fork(); // vfork
if(pid == 0){
while((getppid() != 1)){ //等待父进程先执行完,由 init 进程接管
printf("child pid : %d, wait father : %d\n", getpid(), getppid());
sleep(1);
}
printf("child exit\n");
}
else if(pid > 0){
printf("father: pid = %d\n", getpid());
sleep(2);
printf("father exit\n");
}
else {
printf("fork error\n");
}
return 0;
}
./test8_rece
father: pid = 16749
child pid : 16750, wait father : 16749
child pid : 16750, wait father : 16749
father exit
child exit