首页 > 技术文章 > 数组,父子进程,守护进程

cnlg 2015-01-25 21:48 原文

2015.1.25
星期日,阴天

二维数组a中共有m行n列个元素
从a[0][0]到a[i][j]之间共有i*n+j个元素
p代表第0行第0列的地址,所以元素a[i][j]的地址为 p + i*n+j

a[i][j] == p[i*n+j] == *(p + i*n+j)

在Linux中获得当前进程的PID和PPID的系统调用函数为getpid()和getppid();获得当前PID和PPID后可以将其写入日志备份!

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
printf("the pid of this process is %d\n",getpid());
printf("the ppid of this process is %d\n",getppid());

}
上面程序可以交叉编译下载到目标板上运行!

父进程调用fork()函数就创建了一个子进程,父进程返回子进程的PID,子进程返回值为0;
fork()函数开销很大,不能多次使用。

exec函数族提供了一个在进程中启动另一个进程执行的方法,总共有6个成员函数,使用exec函数时一定
要加上错误判断语句。exec很容易执行失败。

守护进程:daemon ,从被执行开始运转,直到真个系统关闭时才退出!

编写守护进程:

1.创建子进程,然后父进程退出!
pid = fork();
if(pid > 0)
{
exit(0);/*父进程退出*/
}

2.在子进程中创建新会话:重要一步,意义重大! setsid();

3.改变当前目录为根目录 :让子进程脱离父进程的文件工作目录。

4.重设文件权限掩码: 让子进程脱离父进程的文件权限掩码。

如:050 它就屏蔽了文件组拥有者的可读和可执行权限。用函数umask()实现
通常的使用方法是:umask(0)

5.关闭文件描述符

创建一个守护进程的完整实例:创建守护进程,然后让该进程每隔10S向日志文件/tmp/daemon.log写入一句话。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcn1.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

int main()
{
pid_t pid;
int i, fd;
char *buf = "this is a Daemon\n";

pid = fork(); 第一步
if(pid < 0)
{
printf("error fork\n");
exit(1);
}
else if(pid > 0)
{
exit(0); 父进程退出
}

setsid(); 第二步
chdir("/"); 第三步
umask(0); 第四步
for(i = 0; i < getdtablesize(); i++) 第五步
{
close(i);
}

/*这时创建完守护进程,以下开始正式进入守护进程工作*/
while(1)
{
if((fd = open("/tmp/daemon.log",O_CREAT|OWRONLY|O_APPEND.0600))<0)
{
printf("open file error\n");
exit(1);
}
write(fd,buf,strlen(buf) + 1);
close(fd);
sleep(10);
}
exit(0);
}

守护进程出错处理:

gdb无法调试守护进程,因为已经脱离终端,一种通用的办法就是使用syslog服务,将
程序中的出错信息输入到系统日志文件中;

该机制相关的三个syslog函数:openlog();syslog();closelog();
将上面的程序用syslog服务重写;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcn1.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

int main()
{
pid_t pid;
int i, fd;
char *buf = "this is a Daemon\n";

pid = fork(); 第一步
if(pid < 0)
{
printf("error fork\n");
exit(1);
}
else if(pid > 0)
{
exit(0); 父进程退出
}

openlog("daemon_syslog",LOG_PID,LOG_DAEMON);

if((sid = setsid() < 0); 第二步
{
syslog(LOG_ERR,%s\n","setsid");
exit(1);
}

if((sid = chdir("/") < 0); 第三步
{
syslog(LOG_ERR,%s\n","chdir");
exit(1);
}
umask(0); 第四步
for(i = 0; i < getdtablesize(); i++) 第五步
{
close(i);
}

/*这时创建完守护进程,以下开始正式进入守护进程工作*/
while(1)
{
if((fd = open("/tmp/daemon.log",O_CREAT|OWRONLY|O_APPEND.0600))<0)
{
syslog(LOG_ERR,"open“);
exit(1);
}
write(fd,buf,strlen(buf) + 1);
close(fd);
sleep(10);
}
closelog();
exit(0);
}

实验内容:
有三个进程,其中一个为父进程,其余两个是该父进程的子进程。其中一个子进程运行
”ls -l“指令,另一个进程暂停5秒之后异常退出,父进程先用阻塞方式等待第一个子进程的结束,
然后用非阻塞方式等待另一个进程的退出,待收集到第二个子进程结束的信息,父进程就返回!


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void)
{
pid_t child1, child2, child;

/*创建两个子进程*/
child1 = fock();
child2 = fock();

/*子进程1的出错处理*/
if(child1 == -1)
{
printf("child1 fork error\n");
exit(1);
}
else if(child1 == 0) /*在子进程1中调用execlp()函数*/
{
printf("in child1:execute 'ls -l'\n");
if(execlp("ls","ls","-1",NULL) < 0)
{
printf("child1 execlp error\n");
}
}

if(child2 == -1) 子进程2出错处理
{
printf("child2 fork error\n");
exit(1);
}
else if(child2 == 0) 在子进程2中使其暂停5秒
{
printf("in child2:sleep for 5 seconds and then exit\n");
sleep(5);
exit(0);
}
else 在父进程中等待两个子进程的退出
{
printf("in father process:\n");
child = waitpid(child1,NULL,0); 阻塞式等待
if(child == child1)
{
printf("get child1 exit code\n");
}
else
{
printf("error occured!\n");
}

do
{
child = waitpid(child2,NULL,WNOHANG); 非阻塞是等待
if(child == 0)
{
printf("the child2 process has not exited!\n");
sleep(1);
}
}while(child == 0);

if(child == child2)
{
printf("get child2 exit code\n");
}
else
{
printf("error occured!\n");
}
}
exit(0);
}

实验内容:
首先建立起一个守护进程,然后在该守护进程中新建一个子进程,该子进程暂停10秒,
然后自动退出,并由守护进程收集子进程退出的消息,在这里,子进程和守护进程的退出消息都在
系统日志文件中输出,子进程退出后,守护进程循环暂停,其间隔时间为10秒。


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <syslog.h>

int main(void)
{
pid_t child1, child2;
int i;
/*创建子进程*/
child1 = fork();
if(child1 == 1)
{
perror("child1 fork");
exit(1);
}

else if(child1 > 0)
{
exit(0); 父进程退出
}

openlog("daemon_proc_info",LOG_PID,LOG_DAEMON);
/*下面几步是编写守护进程的常规步骤*/
setsid();
chdir("/");
umask(0);
for(i = 0; i < getdtablesize(); i++)
{
chose(i);
}

child2 = fork(); 创建进程2
if(child2 == 1)
{
perror("child2 fork");
exit(1);
}
else if(child2 == 0) 进入进程2
{
syslog(LOG_INFO,"child2 will sleep for 10s"); 在日志中写入字符串
sleep(10);
syslog(LOG_INFO,"child2 is going to exit!"):
exit(0);
}
else
{ 进程child1

waitpid(child2,NULL,0);
syslog(LOG_INFO,"child1 noticed that child2 has exitde");
closelog(); 关闭日志服务
while(1)
{
sleep(10);
}
}

}


**********************************************************************************************************************************************************
**********************************************************************************************************************************************************
**********************************************************************************************************************************************************

推荐阅读