您的位置:首页 > 运维架构 > Linux

linux进程控制

2015-06-01 01:41 274 查看
linux 进程控制 1

首先,linux是一个多任务多进程的操作系统,所以必须要讨论进程的控制。

进程:

进程是一个动态的实体,是程序的一次执行过程,它是操作系统的资源分配的基本单位,简单来说线程和进程区别不大,一个主要的区别就是进程有自己的内存空间,并且占用系统资源。

进程标识:进程的一个重要的标识就是其进程的ID ,PID。

一般使用如下的一些函数来获取ID ,

getpid( ) 获得进程的PID

getppid( ) 获得父进程的PID

getuid( ) 获得实际用户ID

geteuid( ) 获得有效ID

getgid( ) 获得实际的组ID

getegid( ) 获得有效的组ID

进程的状态:

运行状态:正在运行或者等待运行

可中断等待状态:进程正在等待某个事件完成,等待过程就可以被信号或者定时器唤醒

不可中断等待状态:同上但是不能被唤醒,只有在等待的时间完成后,才可以继续进行

僵死状态:进程已经终止,但描述符还存在,直到父进程调用WAIT( )函数释放‘

停止状态:进程因为受到了指示结束或暂停的信号,停止运行。

进程的一些状态标示:

< :高优先级

N :低优先级

L :内存页面不可换出

S :首进程

I :多线程进程

+ : 进程为于前台进程组

进程的控制函数:

fork; 用于创建一个进程

exit: 用于终止进程

exec: 用于执行一个应用程序

wait: 将父进程挂起,等待子进程终止

getpid:获取当前进程的ID

nice: 更改进程的优先级

创建一个进程:

创建一个进程的方式一般有两种:

1。由操作系统创建

2. 由父进程创建

fork( ) 函数是创建一个新进程的唯一方法(init进程是由内核创建)

此函数一般有两个返回值:

1.一个返回值为0,这是子进程fork( )返回的值,为0,标示成功创建

2.另一个值为PID ,表示子进程的ID 。

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t pid;
printf("Process Creation Study\n");
pid = fork();
switch(pid)
{
case 0:
printf("child process is runing ,curpid is %d,parentpid is %d\n",pid,getppid());
break;
case -1:
printf("process creat failed\n");
break;
default:
printf("parent process is runing ,childpid is %d,parentpid is %d\n",pid,getpid());
break;

}
exit(0);
}


这个程序就是使用fock 函数创建一个进程然后返回父进程的ID 和子进程的ID。

一般来说,创建进程之后是父进程先执行还是子进程先执行是不确定的,这个顺序取决于当下使用系统的调度算法。

子进程一般会继承父进程的很多属性:

用户ID,组ID,当前工作目录,根目录,打开的文件,创建文件时使用的屏蔽字,信号屏蔽字,上下文环境,共享的存储段,资源限制等。

同时他们二者还有不同的属性:

进程有它自己的唯一的进程ID。

fork( )的返回值不同,父进程返回子进程的ID ,子进程返回0

每一个子进程的ID 只能是创建他的父进程所给的ID 。

子进程共享父进程的打开的文件描述符,但父进程对文件描述符的改变不会影响子进程中的文件描述符。

子进程不继承父进程的设置的文件锁

子进程不继承父进程的警告

子进程的未决信号集被清空

孤儿进程:

当一个父进程死亡后,他的子进程就变成了孤儿进程,且被init进程收养

vfork( ) 函数与 fork( )函数的比较

1。都是创建一次返回两次,因为前者实际上是调用了后者

2。后者完全复制父进程的资源与地址等,有良好的并发性,后者是共享地址空间与资源

3。前者保证首先运行子进程,当使用了exec,exit 时父进程才会被调用,如果在这些调用之前需要使用父进程就会导致死锁。

死锁:

所谓死锁: 是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程

发生死锁有4个产生条件;

1)互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。

2)请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。

3)不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。

4)环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。

守护进程:

守护进程就是在后台运行的进程,他不占用终端,一般用来执行固定的一些任务。

创建一个守护进程的步骤:

(1)在父进程中执行fork并exit推出;

(2)在子进程中调用setsid函数创建新的会话;

(3)在子进程中调用chdir函数,让根目录 ”/” 成为子进程的工作目录;

(4)在子进程中调用umask函数,设置进程的umask为0;

(5)在子进程中关闭任何不需要的文件描述符

#include<stdio.h>
#include<sys/types.h>

#include<sys/stat.h>
#include<unistd.h>
#include<stdlib.h>
#include<fcntl.h>
#include<signal.h>
#include<sys/param.h>

int creat_daemon(void)
{
int pid;
int i;

signal(SIGTTOU,SIG_IGN);    //忽略IO信号
signal(SIGTTIN,SIG_IGN);
signal(SIGTSTP,SIG_IGN);
signal(SIGHUP,SIG_IGN);

pid = fork();

if(pid > 0){
exit(0);                //结束父进程
}else if(pid < 0){
printf("fork error :%d\n",__LINE__);
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); //将文件屏蔽字设为0

signal(SIGCHLD,SIG_IGN);             //忽略SIGCHLD 信号

return 0;

}

int main()
{
time_t now;
creat_daemon();
while(1){
sleep(1);
remove("daemon.log");
remove("daemon_create.log");
}
return 0;
}


这个程序用来创建一个守护进程,然后这个进程每隔一秒就删除
daemon.log<pre name="code" class="cpp" style="color: rgb(51, 51, 51); line-height: 24px; text-indent: 36px;">daemon_create.log



这两个文件(这是不停生成的日志文件,同理用守护进程不同的生成这两个文件)

进程退出正常退出方法有两种,异常退出方法有三种:

1.正常退出

return退出

调用exit( ) 函数退出

调用_exit( )函数退出

2.异常退出

调用abort( )函数退出

进程收到某个信号自动退出

各种退出方式的比较:

exit( ) , return:前者时函数,接受参数,返回后将控制权限交给系统

后者返回将控制权限交给,调用函数

exit( ) , abort( ): 前者是正常退出,后者是异常退出

exit(exit_code): 参数为0代表正常退出,参数不为0,代表有错误发生

exit( ) ,_exit( ): 两者不再同一个头文件里,后者执行后立即返回给内核,前者需要执行一系列的清除操作,然后将控制权交给内核。

执行新的进程:

#include <unistd.h>

extern char **environ;

int execl(const char *path, const char *arg, ...);

int execlp(const char *file, const char *arg, ...);

int execle(const char *path, const char *arg,

..., char * const envp[]);

int execv(const char *path, char *const argv[]);

int execvp(const char *file, char *const argv[]);

int execvpe(const char *file, char *const argv[],

char *const envp[]);

这是exec一族的全部函数。

execv:此函数通过调用路径名的方式调用可执行文件作为新的进程映像,后面的参数就是命令行参数

execve:此系统调用参数是路径名,后便的参数和main( )函数是对应的

#include <sys/types.h>

#include <sys/wait.h>

pid_t wait(int *status);

pid_t waitpid(pid_t pid, int *status, int options);

wait( )函数就是等待进程结束他的接受值用来存放进程的退出码。

改变进程的优先级,

#include <unistd.h>

int nice(int inc);

他的参数就指定的优先级的数值;

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

int main()
{
pid_t pid;
int  stat_val ;            //标识进程返回符
int oldpri,newpri;          //标识新旧优先级

printf("nice study\n");
pid = fork();               //创建一个进程
switch(pid){
case 0:
printf("child is runing ,curpid is %d,parentpid is %d\n",pid,getppid());  //成功创建展示进程的ID

oldpri = getpriority(PRIO_PROCESS,0);           //获得子进程的原始优先级
printf("old priority = %d\n",oldpri);           //打印子进程的原始优先级
newpri = nice(2);                                //将新优先级设置为2
printf("New priority = %d\n",newpri);           //打印新的优先级
exit(0);
case -1:
perror("process creation failed\n");
break ;
default:
printf("parent is runing ,childpid is %d,Parent is %d\n",pid,getpid());
break ;

}
wait(&stat_val);
exit(0);
}


一个示例程序,其中getproiority 是获得当下进程优先级的函数.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: