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);
}
一般来说,创建进程之后是父进程先执行还是子进程先执行是不确定的,这个顺序取决于当下使用系统的调度算法。
子进程一般会继承父进程的很多属性:
用户ID,组ID,当前工作目录,根目录,打开的文件,创建文件时使用的屏蔽字,信号屏蔽字,上下文环境,共享的存储段,资源限制等。
同时他们二者还有不同的属性:
进程有它自己的唯一的进程ID。
fork( )的返回值不同,父进程返回子进程的ID ,子进程返回0
每一个子进程的ID 只能是创建他的父进程所给的ID 。
子进程共享父进程的打开的文件描述符,但父进程对文件描述符的改变不会影响子进程中的文件描述符。
子进程不继承父进程的设置的文件锁
子进程不继承父进程的警告
子进程的未决信号集被清空
孤儿进程:
当一个父进程死亡后,他的子进程就变成了孤儿进程,且被init进程收养
vfork( ) 函数与 fork( )函数的比较
1。都是创建一次返回两次,因为前者实际上是调用了后者
2。后者完全复制父进程的资源与地址等,有良好的并发性,后者是共享地址空间与资源
3。前者保证首先运行子进程,当使用了exec,exit 时父进程才会被调用,如果在这些调用之前需要使用父进程就会导致死锁。
死锁:
所谓死锁: 是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程
发生死锁有4个产生条件;
(1)在父进程中执行fork并exit推出;
(2)在子进程中调用setsid函数创建新的会话;
(3)在子进程中调用chdir函数,让根目录 ”/” 成为子进程的工作目录;
(4)在子进程中调用umask函数,设置进程的umask为0;
(5)在子进程中关闭任何不需要的文件描述符
#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 是获得当下进程优先级的函数.
版权声明:本文为博主原创文章,未经博主允许不得转载。