linux进程控制

来源:互联网 发布:阿里云oss收费标准 编辑:程序博客网 时间:2024/06/08 09:01

                                                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 是获得当下进程优先级的函数.



0 0
原创粉丝点击