进程
是一个动态的实体,是程序的一次执行过程。
进程和程序的区别在于:进程是动态的,程序是静态的。
为了让计算机在同一时间内能执行更多任务,在进程内部又划分了话多线程。
线程在进程的内部,它是比进程更小的能独立运行的基本单位。
线程基本上不拥有系统资源,它与同属一个进程的其他线程共享进程拥有的全部资源。
进程在执行过程中拥有独立的内存单元,其内部的线程共享进些内存。
一个线程可以创建和撤消另一个线线,同一个进程中的多个线程可以并行执行。
进程标识
#include <unistd.h>
pid_t getpid();//获得进程ID
pid_t getppid();//获得父进程ID
pid_t getuid();//获得进程的实际用户ID
pid_t geteuid();//获得进程有效用户ID
pid_t getgid();//获得进程的实际组ID
pid_t getegid();//获得进程的有效组ID
linux进程结构
代码段:存放可执行代码
数据段:程序的全局变量,常量,静态变量
堆栈段:动态分配的内存变量,函数调用,参数等
linux进程状态
运行状态Runnable
可中断等待状态Sleeping
不可中断等待状态Duninterruptible sleep
僵死状态Zombile
停止状态Traced or stopped
进程控制
创建进程,执行新程序,退出进程及改变进程优先级等。
fork:创建一个新进程
exit:终止进程
exec:执行一个应用程序
wait:将父进程挂起,等待子进程终止
getpid:获得当前进程的进程ID
nice:改变优先级
创建进程:fork是创建新进程的唯一方法
想父进程等待子进程执行完毕后再执行,可以fork后调用wait/waitpid
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid;
printf("Process Creation Study\n");
pid = fork();
switch(pid)
{
case 0:
printf("Child progress,CurPid is %d,ParentPid is %d\n",pid,getppid());
break;
case -1:
perror("process error\n");
break;
default:
printf("Parend process,ChildPid is %d,ParentPid is %d\n",pid,getpid());
break;
}
exit(0);
}
函数最多一个返回值,但fork函数非常特殊,它有两个返回值,即调用一次返回两次。成功调用fork后,当前进程实际上已经分裂成两个进程,一个原父进程,另一个刚刚创建的子进程。
子进程返回0
父进程返回新创建子进程的ID
vfork创建的子进程共享父进程的地址空间,任何数据修改同样为父进程所见,保证子进程先运行,当它调用exec/exit后,父进程才可能被调度运行。
fork子进程会复制父进程资源,开销大,
vfork不会拷贝父进程的地址空间,减小了开销
创建守护进程
在后台运行,没有控制终端与之相连的进程,它独立于控制终端,通常周期性地执行某种任务。
启动方式:
从启动脚本/etc/rc.d中启动
作业规划进程cron启动
用户终端执行
创建守护进程
1用fork产生一个子进程,然后使父进程退出
2调用setsid创建一个新对话期,
3关闭不再需要的文件描述符
4将当前目录改为根目录
5将文件创建时使用的屏蔽字设置为0
6处理SIGCHLD信号
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <time.h>
#include <syslog.h>
int init_daemon()
{
int pid;
int i;
signal(SIGTTOU,SIG_IGN);
signal(SIGTTIN,SIG_IGN);
signal(SIGTSTP,SIG_IGN);
signal(SIGHUP,SIG_IGN);
pid = fork();
if(pid>0)
exit(0);
else if(pid <0)
return -1;
setsid();
pid = fork();
if(pid>0)
exit(0);
else if(pid <0)
return -1;
for(i=0;i < NOFILE ; close(i++));
chdir("/");
umask(0);
signal(SIGCHLD,SIG_IGN);
return 0;
}
int main()
{
time_t now;
init_daemon();
syslog(LOG_USER|LOG_INFO,"test deamon!\n");
while(1)
{
sleep(8);
time(&now);
syslog(LOG_USER | LOG_INFO,"daemon time :%s\n",ctime(&now));
}
}
在使用syslog函数前,首先需要配置/etc/syslog.conf,在该文件最后加
user.*/var/log/test.log,然后重新启动syslog服务。
/etc/init.d/syslog stop
/etc/init.d/syslog start
这样信息就会写入test.log中。
进程退出表示进程结束运行。
正常退出
main执行return
exit
_exit
异常退出
about
执行新程序
子进程通常会调用exec来执行另一个程序
exec调用并没有生成新进程,一个进程一旦调用exec,它本身就死亡了。
#include <unistd.h>
int execve(const char* path,char* const argv[],char * const envp[]);
int execv(const char *path,char* const envp[]);
int execle(const char *path,const char * arg,...);
int execl(const cahr *path,const char* arg,...);
int exevp(const char *file,char * const argv[]);
int execlp(const char *file,const char* arg,...);
env命令查看环境变量
exec函数族可以执行二进制可执行文件,也可以执行SHELL:开头#!/bin/sh
等待进程结束
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid,int *statloc,int options);
#include <sys/types.h>
#include <unistd.h>
int setuid(uid_t uid);
int setgid(gid_t gid);
改变进程的优先级
#include <unistd.h>
int nice(int increment);
#include <sys/resource.h>
int getpriority(int which,int who);
int setpriority(int which,int who,int prio);
保存,方便查阅使用。