进程创建与特殊进程
进程创建:
进程:是正在运行的程序的实例,进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
创建进程的方式有多种,比如:fork、vfork函数,返回值大于0即为父进程,小于0即为错误输出,等于0即为子进程。
fork的特点是:父子进程无先后顺序,独立内存。
vfork的特点是:子进程先于父进程执行,共享内存。
例程如下:
#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t fpid = fork(); // 创建进程,返回值大于0时为父进程,等于0时为子进程,小于0时 // 为创建进程失败
if( fpid > 0 )
{
printf( "parent:%d \n", getpid() ); // 父进程
}
else if( fpid == 0 )
{
printf( "child: %d, %d\n", getpid(), getppid() ); // 子进程,getpid():获取当前进程号
} // getppid():获取父进程号
else
{
perror("fork error"); // perror():错误输出
}
return 0;
}
特殊进程:
在Linux系统中有一些特殊的进程:孤儿进程、僵尸进程、守护进程。它们的形成也各不相同。
孤儿进程:
父进程先于子进程结束时,子进程会被1号进程收养,此时子进程即为孤儿进程。
例程如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t fpid = fork();
if( fpid > 0 )
{
printf( "parent:%d \n", getpid() );
exit(0); // 结束当前进程
}
else if( fpid == 0 )
{
sleep(3); // sleep():延时,此处为延时3秒
printf( "child: %d, %d\n", getpid(), getppid() );
}
else
{
perror("fork error");
}
return 0;
}
僵尸进程:
子进程先于父进程退出,且父进程没有没有收到子进程的退出信息,此时子进程所占用的资源不会释放,即为僵尸进程(zombie)。僵尸进程属于有害进程,要避免出现。
例程如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t fpid = fork();
if( fpid > 0 )
{
while(1)
{
sleep(2);
printf( "parent:%d \n", getpid() );
}
}
else if( fpid == 0 )
{
printf( "child: %d, %d\n", getpid(), getppid() );
exit(0);
}
else
{
perror("fork error");
}
return 0;
}
守护进程:
运行在后台的一种特殊的进程,它独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件,即为守护进程(Daemon)。
例程如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
umask(0); // 调用 umask 将文件模式创建屏蔽字设置为一个已知值,通常为 0,防止子进程 // 继承得来的文件模式权限不够
pid_t fpid = fork();
if( fpid > 0 ) // fork 子进程,然后父进程 exit,这也是后面继续调用 setsid 的先决条件
{
exit(0);
}
setsid(); // 调用 setsid 创建一个新的会话,并且成为一个新进程组的组长,且调用进程没 // 有控制终端,如果先前有联系也会切断
fpid = fork();
if( fpid > 0 )
{
exit(0);
}
chdir("/"); // 将当前工作目录更改为根目录,防止继承来的工作目录在文件系统中无法卸载
close(0); // 关闭不再需要的文件描述符,打开 dev/null 使其具有文件描述符 0、1 和 2 close(1); // 让守护进程不与终端设备相关联,所以输出无处显示,也无法接收输入
close(2);
signal( SIGINT, SIG_IGN); // 忽略 SIGHUP 信号
return 0;
}