进程基本知识
- 进程标识符 pid
类型pid_t
命令ps
ps axf
ps axm
ps ax -L
进程号是顺次向下使用(fd是使用最小的fd)
getpid();
getppid();
- 进程的产生
复制进程并创建进程,执行1次,返回2次
fork()
注意理解关键字:duplicating,意味着拷贝,克隆,一模一样等含义。
fork后父子进程的区别:fork的返回值不一样,pid不同,ppid也不同,未决信号和文件锁不继承,资源利用量清0
init进程:1号,是所有进程的祖先进程
调度器的调度策略来决定哪个进程先运行
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t pid;
printf("[%d]Begin!\n",getpid());
//非常重要 ,输出设备默认是行缓冲区,所以会默认fflush。但是重定向文件./fork >/tmp/out是全缓冲模式 ,父子进程都有begin所以打印两次 .fork之前必须fflush
fflush(NULL);
//pid =0表示子进程 pid>0表示父进程
pid = fork();
if(pid<0)
{
perror("fork()");
}
if(pid==0)
{
printf("[%d]:Child is working!",getpid());
}
else
{
printf("[%d]:Parent is working!",getpid());
}
printf("End");
//getchar();
exit(0);
}
有可能是父进程先调度或者子进程先被调度

输出结果:
如果我们把输出现在在重定向文件上,则会出现两次的begin。这是因为输出设备默认是行缓冲区,所以会默认fflush。但是重定向文件./fork >/tmp/out是全缓冲模式 ,父子进程都有begin所以打印两次,且子进程也是打印父进程的pid .fork之前必须fflush
- fork出的子进程和父进程都对应同一个内存数据对象。谁如果要对该数据对象进行写的操作,就自己复制一个内存数据对象,称为写时拷贝,谁写谁拷贝,然后影响的只是自己进程所指向的对象。
- 进程的消亡及释放资源
wait(int *status) 等待进程状态发生变化
waitpid(pid_t pid,int *status,int options)
waitid()
wait3()
wait4() - exec函数族 当执行这个函数的时候,该函数族执行的二进制文件将替换原有的进程,原有进程的内容都不执行,而是执行exec里的内容。
execl();
execlp();
execle();
execv();
execvp();
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t pid;
puts("Begin!");
fflush(NULL);
fork();
if(pid<0)
{
perror("fork()");
exit(1);
}
if(pid==0)
{
//子进程返回0,父进程返回子进程的pid
execl("/bin/date","date","+%s",NULL);
//如果子进程执行execl失败则会继续执行下面的代码
perror("execl");
exit(1);
}
//父进程等待子进程返回,替他收尸
wait(NULL);
puts("End!");
exit(0);
}
注意:在执行exec函数族之前,也必须先执行fflush(NULL)函数进行刷新缓冲区。

image.png
- 用户权限及组权限
setid()
setreuid()
setregid()
seteuid()
setegid() - 观摩课:解释器文件
- system();
- 进程会计
acct() - 进程时间
times() - 守护进程
查看进程命令:ps -axj
一般指系统开机就会自动运行的进程。守护进程的父进程即ppid=1,pid=pgid=sid
会话session,标识sid
终端
setsid() //创建守护进程
getpgrp()
getpgid()
setpgid()
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FNAME "/tmp/out"
//守护进程例子
static int daemonize(void)
{
int fd;
pid_t pid;
pid = fork();
if(pid<0)
{
perror("fork()");
return -1;
}
if(pid>0)
{
exit(0); //parent
}
fd = open("/dev/null",O_RDWR);
if(fd<0)
{
perror("open()");
return -1;
}
//重定向到0 1 2
dup2(fd,0);
dup2(fd,1);
dup2(fd,2);
if(fd>2)
{
close(fd);
}
//脱离控制终端,父进程也结束了,那他的父进程就会变成1号init进程(守护进程的ppid=1)
setsid();
chdir("/");
//不会产生文件了,就不给权限了。
umask(0);
return 0;
}
int main()
{
File *fp;
if(daemonize())
{
exit(1);
}
fp = fopen(FNAME,"w");
if(fp==NULL)
{
perror("fopen()");
exit(1);
}
for(i=0;;i++)
{
fprintf(fp,"%d\n",i);
fflush(fp);
sleep(1);
}
exit(0);
}
- 系统日志