1. 进程间打开文件的继承

1.1. 用fork继承打开的文件

fork以后的子进程自动继承了父进程的打开的文件,继承以后,父进程关闭打开的文件不会对子进程造成影响。

示例:

#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

int main()

{

char szBuf[32] = {'\0'};

int iFile = open("./a.txt", O_RDONLY);

if(fork() > 0){//parent process

close(iFile);

return 0;

}

//child process

sleep(3); //wait for parent process closing fd

if(read(iFile, szBuf, sizeof(szBuf)-1) < 1){

perror("read fail");

}else{

printf("string:%s\n",szBuf);

}

close(iFile);

return 0;

}

1.2. 守护进程

Daemon运行在后台也称作“后台服务进程”。 它是没有控制终端与之相连的进程。它独立与控制终端、通常周期的执行某种任务。那么为什么守护进程要脱离终端后台运行呢?守护进程脱离终端是为了避免进程在执行过程中的信息在任何终端上显示并且进程也不会被任何终端所产生的任何终端信息所打断。那么为什么要引入守护进程呢?由于在linux中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依赖这个终端,这个终端就称为这些进程的控制终端。当控制终端被关闭时,相应的进程都会自动关闭。但是守护进程却能突破这种限制,它被执行开始运转,直到整个系统关闭时才退出。几乎所有的服务器程序如Apache和wu-FTP,都用daemon进程的形式实现。很多Linux下常见的命令如inetd和ftpd,末尾的字母d通常就是指daemon。

守护进程的特性:

1> 守护进程最重要的特性是后台运行。

2> 其次,守护进程必须与其运行前的环境隔离开来。这些环境包括未关闭的文件描述符、控制终端、会话和进程组、工作目录已经文件创建掩码等。这些环境通常是守护进程从父进程那里继承下来的。

3> 守护进程的启动方式

daemon进程的编程规则

l 创建子进程,父进程退出:

调用fork产生一个子进程,同时父进程退出。我们所有后续工作都在子进程中完成。这样做我们可以交出控制台的控制权,并为子进程作为进程组长作准备;由于父进程已经先于子进程退出,会造成子进程没有父进程,变成一个孤儿进程(orphan)。每当系统发现一个孤儿进程,就会自动由1号进程收养它,这样,原先的子进程就会变成1号进程的子进程。代码如下:

pid = fork();

if(pid>0)

exit(0);

l 在子进程中创建新会话:

使用系统函数setsid()。由于创建守护进程的第一步调用了fork函数来创建子进程,再将父进程退出。由于在调用fork函数的时候,子进程全盘拷贝了父进程的会话期、进程组、控制终端等,虽然父进程退出了,但会话期、进程组、控制终端并没有改变,因此,还不是真正意义上的独立开来。而调用setsid函数会创建一个新的会话并自任该会话的组长,调用setsid函数有下面3个作用:让进程摆脱原会话的控制,让进程摆脱原进程组的控制,让进程摆脱原控制终端的控制;

进程组:是一个或多个进程的集合。进程组有进程组ID来唯一标识。除了进程号(PID)之外,进程组ID(GID)也是一个进程的必备属性。每个进程都有一个组长进程,其组长进程的进程号等于进程组ID。且该进程组ID不会因为组长进程的退出而受影响。

会话周期:会话期是一个或多个进程组的集合。通常,一个会话开始于用户登录,终止于用户退出,在此期间该用户运行的所有进程都属于这个会话期。

控制终端:由于在linux中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依赖这个控制终端。

l 改变当前目录为根目录:

使用fork函数创建的子进程继承了父进程的当前工作目录。由于在进程运行中,当前目录所在的文件是不能卸载的,这对以后的使用会造成很多的不便。利用chdir("/");把当前工作目录切换到根目录。

l 重设文件权限掩码:

umask(0);将文件权限掩码设为0,Deamon创建文件不会有太大麻烦;

l 关闭所有不需要的文件描述符:

新进程会从父进程那里继承一些已经打开了的文件。这些被打开的文件可能永远不会被守护进程读写,而它们一直消耗系统资源。另外守护进程已经与所属的终端失去联系,那么从终端输入的字符不可能到达守护进程,守护进程中常规方法(如printf)输出的字符也不可能在终端上显示。所以通常关闭从0到MAXFILE的所有文件描述符。

for(i=0;i<MAXFILE;i++)

close(i);

(注:有时还要处理SIGCHLD信号signal(SIGCHLD, SIG_IGN);防止僵尸进程(zombie))

下面就可以添加任何你要daemon做的事情

示例:

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/stat.h>

void Daemon()

{

const int MAXFD=64;

int i=0;

if(fork()!=0) //父进程退出

exit(0);

setsid(); //成为新进程组组长和新会话领导,脱离控制终端

chdir("/"); //设置工作目录为根目录

umask(0); //重设文件访问权限掩码

for(;i<MAXFD;i++) //尽可能关闭所有从父进程继承来的文件

close(i);

}

int main()

{

Daemon(); //成为守护进程

while(1){

sleep(1);

}

return 0;

}

Example:

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <syslog.h>

#include <sys/stat.h>

#include <time.h>

main()

{

int i = 0;

if(fork() > 0)

exit(0);

setsid();

chdir("/");

umask(0);

for(; i < 64; i++)

{

close(i);

}

i = 0;

while(i < 10)

{

printf("%d\n",i);

time_t ttime;

time(&ttime);

struct tm *pTm = gmtime(&ttime);

syslog(LOG_INFO,"%d %04d:%02d:%02d", i, (1900 + pTm->tm_year), (1 + pTm->tm_mon), (pTm->tm_mday));

i++;

sleep(2);

}

}

通过查看vi /var/log/messages

Linux进程控制(三)的更多相关文章

  1. Linux进程控制(二)

    1. 进程的创建 Linux下有四类创建子进程的函数:system(),fork(),exec*(),popen() 1.1. system函数 原型: #include <stdlib.h&g ...

  2. Linux进程控制(一)

    1. Linux进程概述 进程是一个程序一次执行的过程,它和程序有本质区别.程序是静态的,它是一些保存在磁盘上的指令的有序集合:而进程是一个动态的概念,它是一个运行着的程序,包含了进程的动态创建.调度 ...

  3. Linux - 进程控制 代码(C)

    进程控制 代码(C) 本文地址:http://blog.csdn.net/caroline_wendy 输出进程ID.getpid(). 代码: /*By C.L.Wang * Eclipse CDT ...

  4. Linux 进程控制

    分享知乎上看到的一句话,共勉: 学习周期分为学习,思考,实践,校正四个阶段,周期越短,学习效率越高. 前面讲的都是操作系统如何管理进程,接下来,看看用户如何进行进程控制. 1.进程创建 先介绍一下函数 ...

  5. linux c编程:进程控制(三)_exec函数

    fork()函数通过系统调用创建一个与原来进程(父进程)几乎完全相同的进程(子进程是父进程的副本,它将获得父进程数据空间.堆.栈等资源的副本.注意,子进程持有的是上述存储空间的“副本”,这意味着父子进 ...

  6. Linux进程控制——exec函数族

    原文:http://www.cnblogs.com/hnrainll/archive/2011/07/23/2114854.html 1.简介 在Linux中,并不存在exec()函数,exec指的是 ...

  7. Unix环境高级编程—进程控制(三)

    一.解释器文件 解释器文件属于文本文件,起始行形式为: #! pathname[optional-argument] 我们创建一个只有一行的文件如下: #!/home/webber/test/echo ...

  8. LINUX进程控制

    1. 引言 一个程序是存储在文件中的机器指令序列.一般它是由编译器将源代码编译成二进制格式的代码.运行一个程序意味着将这个机器指令序列载入内存然后让处理器(cpu)逐条执行这些指令. 在Unix术语中 ...

  9. linux进程篇 (三) 进程间的通信2 信号通信

    2. 信号通信 用户空间 进程A <----无法通信----> 进程B -----------------|--------------------------------------|- ...

随机推荐

  1. windows_phone指定时间后执行函数

    开发windows phone 应用程序时需要在一段指定的时间后执行某些函数,于是乎想到了通过DispatcherTimer类来实现,再在.Tick后面添加自己想要的事件 DispatcherTime ...

  2. js中常用数组方法concat join push pop slice splice shift

    javascript给我们很多常用的 数组方法,极大方便了我们做程序.下面我们来介绍下常用的集中数组方法. 比如 concat() join() push() pop() unshift() shif ...

  3. PHP soap Web Service 使用SoapDiscovery.class.php 生成wsdl文件

    PHP soap web service 使用wsdl文件 demo: ============================================================== 服 ...

  4. 利用MariaDB Galera Cluster实现mariadb的多主复制

    一.MariaDB Galera Cluster概要: .简述: MariaDB Galera Cluster 是一套在mysql innodb存储引擎上面实现multi-master及数据实时同步的 ...

  5. iOS验证码倒计时(GCD实现)

    + (void)verificationCode:(void(^)())blockYes blockNo:(void(^)(id time))blockNo { __block ; //倒计时时间 d ...

  6. Android的事件处理机制(一)------基于回调机制的事件处理

    Android平台的事件处理机制有两种,一种是基于回调机制的,一种是基于监听接口的,现介绍第一种:基于回调机制的事件处理.Android平台中,每个View都有自己的处理事件的回调方法,开发人员可以通 ...

  7. HDU 2059 龟兔赛跑(动态规划)

    龟兔赛跑 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  8. Apache设置禁止访问网站目录(目录列表显示文件)

    默认apache在当前目录下没有index.html入口就会显示目录.让目录暴露在外面是非常危险的事,如下操作禁止apache显示目录,希望文章对各位有帮助. 进入apache的配置文件 httpd. ...

  9. ExtJs布局之Column

    <!DOCTYPE html> <html> <head> <title>ExtJs</title> <meta http-equiv ...

  10. (3)初次接触off

    boss布置任务了,要读入off文件,生成能显示出来的可执行文件,完成不了就要滚蛋 目前的东西还是不用保密的,到后面我就要设密码了 好,.off文件是什么? OFF,Object File Forma ...