内核线程(thread)和 守护进程(daemon)
<注1>。
内核线程也可以叫内核任务,它们周期性地执行,例如,磁盘高速缓存的刷新,网络连接的维护,页面的换入换出等等。在Linux中,内核线程与普通进程有一些本质的区别,从以下几个方面可以看出二者之间的差异:
· 内核线程执行的是内核中的函数,而普通进程只有通过系统调用才能执行内核中的函数。
· 内核线程只运行在内核态,而普通进程既可以运行在用户态,也可以运行在内核态。
· 因为内核线程指只运行在内核态,因此,它只能使用大于PAGE_OFFSET(3G)的地址空间。另一方面,不管在用户态还是内核态,普通进程可以使用4GB的地址空间。
内核线程是由kernel_thread( )函数在内核态下创建的,这个函数所包含的代码大部分是内联式汇编语言,但在某种程度上等价于下面的代码:
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { pid_t p; p = clone( 0, flags | CLONE_VM ); if ( p ) /* parent */ return p; else { /* child */ fn(arg); exit( ); } } |
系统中大部分的内核线程是在系统的启动过程中建立的。
注1:
(1)Linux 守护进程概述
(4)Linux 守护进程管理
守护进程
守护进程( daemon )是生存期长的一种进程。它们常常在系统引导装入时起动,在系统关闭时终止。因为它们没有控制终端,所以说它们是在后台运行的。linux 系 统有很多守护进程,它们执行日常事物活动。
所有守护进程都以超级用户(用户I D 为0 )的优先权运行。
没有一个守护进程具有控制终端—终端名称设置为问号(?)、终端前台进程组I D 设置为-1 。缺少控制终端可能是精灵进程调用了s e t s i d 的结果。
除u p d a t e 以外的所有精灵进程都是进程组的首进程,对话期的首进程,而且是这些进程组和对话期中的唯一进程。u p d a t e 是它所在进程组和对话期(中的唯一进程,但是该进程组的首进程(可能也是该对话期的首进程)已经终止。
所有这些守护进程的父进程都是i n i t 进程。
守护进程编程5 步:
1. 首先做的是调用fork(), 然后使父进程exit, 这样做实现了以下几点, 如果该守护进程是由一条简单shell 启动的, 那么使父进程终止使 得shell 认为这条命令已经执行完成。第二, 子进程继承了父进程的进程组ID, 这就保证了子进程不是一个进程组的首进程. 这对于下面就要做的 setsid 调用是必要的前提
2. 调用setsid 以创建一个新的会话, 并担任该会话组的组长. 调用setsid 的作用由三个:
-
成为新的会话组的首进程
-
成为新的进程组的首进程
-
脱离控制终端
setsid() 函数格式:
#include <sys/types.h>
#incldue <unistd.h>
pid setsid() 成功时返回该进程组的ID, 失败时返回-1
3. 改变当前目录为根目录
chdir(“/”);
4. 重设文件权限掩码
umask(0);
由继承得来的文件方式创建屏蔽字可能会拒绝设置某些许可权, 例如: 若守护进程要创建一个组可读写的文件,
而继承的文件方式创建屏蔽字, 屏蔽了这两种许可权限, 则所要求的组可读写就不起作用.
5. 关闭不在需要的文件描述符
守护进程的出错处理:
守护进程完全脱离了控制终端,因此,不能像其他程序一样通过输出错误信息到控制台的方式来通知程序员。
通常的办法是使用 syslog 服务,将出错信息输入到“ /var/log/message” 系统日志文件中去。
Syslog 是 linux 中的系统由于日志管理服务通过守护进程 syslog 来维护。
守护进程的实例 :
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#define MAXFILE 65535 // 最大的文件描述符
int main()
{
pid_t pc;
int i,fd,len;
char *buf="This is a Dameon/n";
len =strlen(buf);
pc=fork();
if(pc<0)
{
printf("error fork/n");
exit(1);
}
else if(pc>0)
exit(0); // 父进程退出 , 这个子进程变成孤儿进程 , 由 init 进程接管 ,
setsid(); // 变为后台程序
chdir("/");
umask(0); // 对所有的权限开放
for(i=0;i<MAXFILE;i++)
close(i); // 关闭所有的不需要的文件描述符
while(1) // 守护进程实现的服务
{
if((fd=open("/tmp/dameon.log",O_CREAT|O_WRONLY|O_APPEND,0600))<0) //open不是基于缓
冲区的,前面是要打开的文件, O_CREAT如果文件不存在就创建它,可读写,可追加,0600是访问权限最前面
的0表示文件的类型
{
perror("open");
exit(1);
}
write(fd, buf, len+1); //open函数获得了文件描述符,用write把buffer中的内容写入文件中
close(fd);
sleep(10);
}
}
查看结果
fighter@fighter:/tmp$ cat dameon.log
This is a Dameon
This is a Dameon
This is a Dameon
This is a Dameon
This is a Dameon
This is a Dameon
This is a Dameon