进程概述
进程基本概念
定义:正在进行(执行)的程序
进程三种状态的转化关系
进程控制编程
fork()函数
功能:创建一个子进程,子进程是父进程复制品,返回值有两个,父进程中返回进程号,子进程返回0。
缺点:开销大,速度慢
示例代码:
/* fork.c */
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
pid_t result;
result = fork();/*调用fork函数,其返回值赋值给result*/
if(result == -1)/*通过result的值来判断fork函数的返回情况,首先进行出错处理*/
{
printf("Fork error\n");
}
else if (result == 0) /*返回值为0代表子进程*/
{
printf("The return value is %d\nIn child process!!\nThe child process PID is %d\n\n",result,getpid());
}
else /*返回值大于0代表父进程*/
{
printf("The return value is %d\nIn father process!!\nThe father process PID is %d\n",result,getpid());
}
return result;
}
exec函数族
Linux中没有exec()函数,这里是六个以exec开头的函数
前四位 | 均为exec | ||||||
第五位 |
| ||||||
第六位 |
|
exit()和_exit()函数
二者都是用来终止进程的。
区别:exit()调用exit系统之前会把文件缓冲区的内容协会文件
exit()示例代码:
/* exit.c 由于printf()函数使用的是缓冲I/O 方式,该函数在遇到“\n”换行符时自动从缓冲区中将记录读出。
示例中就是利用这个性质来进行比较的。
*/
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("Using exit...\n");
printf("This is the content in buffer");
exit(0);
}
_exit()示例代码:
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("Using _exit...\n");
printf("This is the content in buffer");
_exit(0);
}
调用exit()函数的时候缓冲区能正常输出,_exit()无法输出缓冲区记录
wait()和waitpid()函数
作用:用于阻塞父进程
区别:waitpid不一定要等待第一个终止的子进程
示例代码:
/* waitpid.c */
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
pid_t pc, pr;
pc = fork();
if (pc < 0)
{
printf("Error fork\n");
}
else if (pc == 0) /*子进程*/
{
/*子进程暂停5s*/
printf("The Child process is going to sleep(5);\n");
sleep(5);
printf("The Child process wake up;\n");
/*子进程正常退出*/
exit(0);
}
else /*父进程*/
{
/*循环测试子进程是否退出*/
do
{
/*调用waitpid,且父进程不阻塞*/
/*WNOHANG就是不阻塞的意思*/
pr = waitpid(pc, NULL, WNOHANG);
/*若子进程还未退出,则父进程暂停1s*/
if (pr == 0)
{
printf("The child process has not exited\n");
sleep(1);
}
} while (pr == 0);
/*若发现子进程退出,则waitpid()返回值为子进程进程号*/
if (pr == pc)
{
printf("\nThe father process quit because the child process quit.\n");
printf("The return of waitpid() is the child process PID : %d\n",pr);
}
else
{
printf("Some error occured.\n");
}
}
return 0;
}
守护进程
什么是守护进程?
独立于控制终端,周期性执行某种任务或者等待处理某些发生的事件的特殊进程
守护进程编写步奏
1.创建子进程,父进程退出
pid = fork();//获取fork函数返回的返回值
if(pid>0)//如果是进程号说明是父进程
{
exit(0);//退出
}
2.在子进程中创建新的会话
使用setsid()函数创建一个新的会话
作用:让进程摆脱(原会话,原进程组,原控制终端)
3.改变当前目录为根目录
使用chdir("/")函数更改工作目录到根目录
4.重设文件权限掩码
umask(0)
5.关闭文件描述符
close()
示例代码:
/* dameon.c 创建守护进程实例 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <syslog.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); /*第四步 设置文件权限为666*/
/*
文件权限掩码umask是指屏蔽掉文件权限中的对应位。
比如文件权限掩码050,5=4+1即r和x权限,5出现在第2位,说明是该文件同组的其他用户对该文件具有的读和可执行权限。
chmod是设哪个位,哪么哪个位就有权限,而umask是设哪个位,则哪个位上就没权限。
所以文件掩码050就屏蔽了文件组拥有者的可读与可执行权限。
*/
for(i = 0; i < getdtablesize(); i++) /*第五步 关闭文件描述符;getdtablesize()表示进程所能打开的最大文件数*/
{
close(i);
}
/*这时创建完守护进程,以下开始正式进入守护进程工作*/
while(1)
{
if ((fd = open("/tmp/daemon.log", O_CREAT|O_WRONLY|O_APPEND, 0600)) < 0)
{
printf("Open file error\n");
exit(1);
}
write(fd, buf, strlen(buf) + 1); /*每隔10秒向/tmp/daemon.log文件写入字符串:This is a Daemon\n*/
close(fd);
sleep(10);
}
exit(0);
}