进程相关(创建-回收-exec-守护进程)
1.进程的创建与回收
1.1创建
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid = fork();
if( pid < 0 ){
perror( "fork" );
return 0;
}else if( 0 == pid){
printf( "这是子进程!\n" );
}else{
printf( "这是父进程!\n" );
}
}
1.2 回收子进程
wait( &status );
阻塞回收,WEXITSTATUS(status)
成功时返回回收的子进程的进程号;失败时返回EOF
若子进程没有结束,父进程一直阻塞
若有多个子进程,哪个先结束就先回收
status 指定保存子进程返回值和结束方式的地址
status为NULL表示直接释放子进程PCB,不接收返回值
#include <unistd.h>
pid_t waitpid(pid_t pid, int *status, int option);
参数:
pid
pid>0时,等待该pid的子进程结束,不管其它子进程。
pid=-1时,等待任意子进程退出,此时waitpid和wait的作用相同。
pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。
pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。
options
options提供了一些额外的选项来控制waitpid,目前在Linux中只支持
WNOHANG
和WUNTRACED
两个选项,
这是两个常数,可以用"|"运算符把它们连接起来使用
WNOHANG
:若由pid指定的子进程未发生状态改变(没有结束),则waitpid()不阻塞,立即返回0
WUNTRACED
: 返回终止子进程信息和因信号停止的子进程信息
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int status;
pid_t pid = fork();
if( pid < 0 ){
perror( "fork" );
return 0;
}else if( 0 == pid){
printf( "这是子进程!\n" );
exit( 0 );
}else{
printf( "这是父进程!\n" );
//wait( &status );阻塞回收
int rpid = waitpid( -1, &status, WNOHANG );
printf( "子进程返回状态值status = %x \n", WEXITSTATUS(status) );
}
return 0;
}
2.exec函数族与守护进程
2.1 exec函数族
背景:
fork创建子进程之后,
子进程和父进程执行相同的代码,
但是在实际开发中,我们希望父子进程执行不同的代码。
作用:执行指定的程序
#include <unistd.h>
int execl(const char *path, const char *arg, …);
int execlp(const char *file, const char *arg, …);
成功时执行指定的程序;失败时返回EOF
path 执行的程序名称,包含路径
arg… 传递给执行的程序的参数列表
file 执行的程序的名称,在PATH中查找
两个函数区别:
execlp不需要写文件名全路径,在PATH查找
最后一个参数必须用空指针(NULL)作结束
进程当前内容被指定的程序替换,但进程号不变
第0个参数必须要写,虽然它没有使用
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, const char *argv[])
{
pid_t child1, child2, child;
//创建两个子进程
child1 = fork();
child2 = fork();
//子进程1的出错处理
if(-1 == child1){
perror("1 fork error");
exit(1);
}else if(0 == child1){ //子进程1中执行其他程序
printf("调用execlp(),执行ls -l\n");
if(execlp("ls", "ls", "-l", NULL) < 0){
printf("child1 execlp error\n");
}
}
//子进程2的出错处理
if(-1 == child2){
perror("child2 fork error");
exit(1);
}else if(0 == child2){ //子进程2中执行其他程序
printf("暂停5秒\n");
sleep(5);
exit(0);
}else{
printf("在父进程中等待两个子进程的退出\n");
child = waitpid(child1, NULL, 0);//非阻塞等待
if(child == child1){ //进程1退出
printf("Get child1 exit code\n");
}else{
printf("error!\n");
}
do
{
child = waitpid ( child2, NULL, WNOHANG ) ;//非阻塞式等待,需要循环等待
if ( child == 0 ){
printf("子进程2还未结束\n");
sleep(1);
}
}while ( 0 == child);
if ( child == child2 ){
printf("Get child2 exit code\n");
}else{
printf("Error!\n");
}
}
exit ( 0 ) ;
}
2.2 守护进程
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main ()
{
FILE* fp;
time_t t;
pid_t pid = fork();
if( pid < 0 ){
perror("fork");
return 0;
}
//1.创建子进程,父进程退出
else if( pid > 0 ){
exit( 0 );
}
printf("\nbefore setsid:sid=%d pid=%d gpid=%d\n",
getsid( getpid() ), getpid(), getpgid( getpid() ) );
//2.设置sid
if( setsid() < 0 ){
perror("setsid");
exit( 0 );
}
printf("after setsid:sid=%d pid=%d gpid=%d\n",
getsid( getpid() ), getpid(), getpgid( getpid() ) );
//3.更改工作目录
chdir("/tmp");
//4.设置文件掩码
if( umask(0) < 0 ){
perror("umask");
exit(0);
}
//5.关闭文件描述符
close(0);
close(1);
close(2);
//打开文件time.log
if( (fp = fopen("time.log" , "a")) == NULL){
perror("fopen");
exit(-1);
}
while(1){
time( &t );
fprintf( fp, "%s", ctime(&t) );
fflush( fp );
sleep(1);
}
return 0;
}
time() 函数:
获取系统当前的时间,返回一个以秒为单位的整数值。
ctime() 函数:
将time_t 类型的时间值转换为一个字符串,
函数返回的字符串是一个指向静态分配缓冲区的指针。
fprintf() 函数:
将格式化的数据写入文件或流中
fflush() 函数:
将缓冲区中的数据写入文件或流中。
sleep() 函数:
使进程挂起指定的时间,以秒为单位。