注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Under the bule sky

Get what I want "cause I ask for it.

 
 
 

日志

 
 

Linux进程&线程--进程及相关函数Ⅰ  

2014-08-11 13:06:49|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

一 进程和程序区别 

 

   程序:存储在磁盘上可执行指令的集合,是一个文件.典型格式elf elf - format of Executable and Linking Format (ELF) 

      files)。静态属性。

   进程:程序的一次执行过程,伴随资源的分配和释放。动态属性。

   进程执行的时候需要的资源:内存,时间片,CPU ,文件。


二 Linux 进程 

 

   (1)进程数据组成:


      |            程序              |          系统            |

      代码段,rodata段,data段 ,bss段, 堆和栈,一组寄存器的值 

 

      linux系统下用struct task_struct 结构体描述一个进程(也有称PCB进程控制块)

      进程表项即struct task_struct *指针(相当于一个户口本),指向一个对应的进程。

 

   (2)进程的标识 

 

      PID  : 进程本身的标识,内核用于区分不同进程 getpid(2)   (PID和PPID都是非零的正整数)。

      PPID : 进程的父进程标识 getppid(2)。

 

      用户通过进程名也可区分不同进程。

      不同进程可能进程名相同,PID一定不同。

 

      查看进程的PID,PPID (process identity number)

      ps -ef | grep 进程名 

 6.Linux进程线程 - 戴↑Ω听歌 - ∞

 

      进程是程序执行和资源管理的最小单位。


   (3)进程的分类 

 

      a.交互进程   b.批处理进程  c.守护进程(在后台运行,不随终端设备的关闭而结束执行)

 

三 进程相关命令


   ps -ef ps aux命令用法及显示

   killkillall命令给进程发信号

   top命令介绍

   nicerenice命令改变进程优先级

   bg fg

 

   (1)ps 

 

      a.查看PID,PPID

      例如:ps -ef | grep 进程名/进程ID

 

      b.查看进程的状态

 

      ps aux | grep 进程名/进程ID


 6.Linux进程线程 - 戴↑Ω听歌 - ∞

 

      R:运行或就绪状态  D:不可中断的等待态  S:可中断的等待态  T:停止态 Z:僵尸态(进程结束了,其父进程没有

      收尸处理)。

      +表示进程在前台进程组中




Linux进程线程--进程及相关函数Ⅰ - 戴↑Ω听歌 - Under the bule sky

 

 

   (2)kill 

      功能:给指定PID进程发信号 

 

      常用的用法:

      kill -信号宏名 PID 

      kill -信号编号 PID 

 

      kill -9 pid

      kill -SIGKILL pid

      kill -KILL pid

 

      查看可发送信号列表:kill -l

 6.Linux进程线程 - 戴↑Ω听歌 - ∞

    (3)killall 

      功能:给指定同名的进程发信号

 

      常用的用法信号指定与kill类似:

      killall -信号  进程名 

 

   (4)nice 

      功能:运行程序的时候,间接指定进程的优先级

      默认进程运行时优先级PR20

 

      可能过top命令查看进程的NI(nice)

6.Linux进程线程 - 戴↑Ω听歌 - ∞

 

      其中PR和 NI 值,都会影响进程执行的优先级:

      NINice值,PR是优先级,Nice值是进程的一个属性,PR是根据Nice排序的

      Priority/PR 由 OS 内核动态调整,用户不能调整(PR 值越低,进程执行的优先级越高)

      Nice/NI 用户可以自己调整

      相互关系:有个一般公式,PR(new) = PR(old) + NI

      但是,PR 是 OS 动态调整的,但是 PR 的最终值还需要由 OS 分析决定的(虽然 NI 会影响 PR

 

      nice [-20,19],nice值越小,会使进程的优先级越高 

 

      例如:运行程序的时候,指定nice值 

      nice -18 ./a.out 

 

      指定一个负的nice ,此时会使进程优先级提高,需要root权限

      sudo nice --15 ./a.out 

 

   (5)renice 

      功能:改变正在运行的进程优先级 

      如果是将进程优先级升高需要root权限,即加sudo执行

 

      renice nice值 PID 

 

      例如:

      renice 10  PID 

      sudo renice -10 PID

 

      进程详细信息 /proc目录下

      $cat /proc/$$/status

 

      Name: bash

      State: S (sleeping)

      Tgid: 17910

      Pid: 17910

      PPid: 17675

      TracerPid: 0

      Uid: 1000 1000 1000 1000

      Gid: 1000 1000 1000 1000

 

      $cat /proc/$$/fdinfo/1

 

      pos: 0

      flags: 02

 6.Linux进程线程 - 戴↑Ω听歌 - ∞

 

   (6)bg

      将挂起的进程放到后台运行

      执行一个耗时程序

      $./a.out 

 

      ^Z  # ctrl + z向进程发信号SIGTSTP使交互进程被挂起(暂停)

      [1]+  Stopped                 ./a.out

      $bg 1       #根据[jobs]号将对应任务放到后台运行

      [1]+ ./a.out &

 

   (7)fg

      将后台运行的进程放到前台运行

      后台运行一个程序

      $./a.out &(运行程序后面加上&,可以查看进程的job号)

6.Linux进程线程 - 戴↑Ω听歌 - ∞

 

      [1] 18855       #显示后台进程的[jobs]PID

 

      $fg 1       #根据jobs号将对应任务放到前台运行

      ./a.out 


 

五 创建子进程 

 

   pid_t fork(void)

   功能:创建子进程 

   返回值失败返回-1;给父进程返回子进程PID,给子进程返回

 

   创建子进程的过程:拷贝父亲的堆,栈,rodata段,data段,bss段,一组寄存器的值,其中代码段共享 

 

   注意:

   1.fork之后父,子进程谁先执行是不确定,取决系统的调度算法  

   2.fork之后,父子进程都是从fork下一条语句开始执行

   3.fork时,父进程的正文段和子进程共享,数据段,堆栈段,堆,打开的文件等资源均让子进程拷贝一份

   4.fork之后,父子进程各自拥用独立4G地址空间,相互并不影响

   5.fork后子进程继承父进程打开的文件,与父进程使用相同的文件表项,

     对一个文件共用offset

 

   父子进程打开文件的方式

   1.fork前打开文件,父子进程共用相同的文件表项

   2.fork后父子进程各自独立打开同一文件,各自拥用指向同一文件的文件表项,

   (当打开方式中有O_TRUNC时,后打开文件的进程会将先打开进程写入数据清0)

   3.fork前打开文件,父子进程共用相同的文件表项,子进程先关闭文件,再重新打开一次同一文件,打开时不用O_TRUNC,不会产生第2         种方式的问题。

 


 

六 exec函数族 

 

   功能:在一个进程中载入执行另外程序 

   过程:exec用执行的程序,替换原进程的数据段,代码段,堆栈段,只保留原进程的PID 

 

   1.l : list(给可执行文件,以列举的方式传递参数)

 

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

      int execl(可执行所在的路径,可执行文件名,参数1,参数2,..,NULL);

 

      注意:

      1.execl()函数虽为可变参数,但参数类型均要求为const char *字符指针类型

      2.execl()函数要求第一个参数指定可执行程序有效路径,之后第一个参数必须为可执行文件名

      并且,最后以一个NULL为结束,所以execl()函数至少需要三个参数

 

      例如:执行ls -l

 

      execl("/bin/ls","ls","-l",NULL);

 

   2.p : PATH(PATH环境变量搜索可执行文件)

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

      int execlp(可执行文件名,可执行文件名,参数1,参数2,..,NULL);

 

      例如:执行ls -l

      execlp("ls","ls","-l",NULL);

 

   3.v : 参数在传递的时候,存放在指针数组vector

      char *p_arr[] = {可执行文件名,参数1,参数2,...,NULL};

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

      int execv(可执行文件路径,指针数组名);

 

      int execl(可执行所在的路径,可执行文件名,参数1,参数2,..,NULL);

 

      例如:执行./a.out src.c dest.c

 

      execl("./a.out","a.out","src.c","dest.c",NULL);

 

      char *p_arr[] = {"a.out","src.c","dest.c",NULL};

      execv("./a.out",p_arr);

 


 

   v and p

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

   int execvp(可执行文件名,指针数组名);

 

   例:执行 ls -l .

   char *p_arr[] = {"ls","-l",".",NULL};

   execvp("ls",p_arr);

 

   exec函数簇的各函数区别

    1.execve(2)是系统调用外,其它函数均为库函数

    2.可执行文件查找方式     p:PATH环境变量提供路径前缀

    3.参数表传递方式         l:list列举  v:vector 指针数组

    4.环境变量的使用         e:environ 通过指针数组指定新程序的执行环境

 





七、return,exit,_exit 函数

1.exit(3) 库函数
exit - cause normal process termination 
 #include <stdlib.h> 
 void exit(int status); 
 The C standard specifies two constants, EXIT_SUCCESS and EXIT_FAILURE, that may be passed to exit() to indicate successful or unsuccessful termination, respectively.

2.    _exit(2) 系统调用
_exit, _Exit - terminate the calling process 
 #include <unistd.h> 
void _exit(int status); 
 The function _exit() terminates the calling process "immediately". Any open file descriptors belonging to the process are closed; any children of the process are inherited by process 1, init, and the process's parent is sent a SIGCHLD signal.

3.return:结束一个函数的调用,主要用函数返回  

三者的区别:
exit ,_exit :结束一个进程的运行 
 exit,_exit区别:exit函数结束进程时候,会刷新缓存,而_exit直接结束进程,不刷新缓存
6.Linux进程线程--进程及相关函数Ⅰ - 戴↑Ω听歌 - ∞
6.Linux进程线程--进程及相关函数Ⅰ - 戴↑Ω听歌 - ∞
 
 
八、 wait 和 waitpid 
1.wait ()
pid_t wait(int *status); 
功能:回收处于僵尸态的子进程,如果没有僵尸态的子进程则阻塞,如果没有子进程会立即返回 
参数: 
status 获得子进程退出的状态,如果不想获得子进程状态,status可以为NULL 
WIFEXITED(status) 
 returns true if the child terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main(). WEXITSTATUS(status) 
 returns the exit status of the child. This consists of the least significant 8 bits of the status argu‐ ment that the child specified in a call to exit(3) or _exit(2) or as the argument for a return statement in main(). This macro should only be employed if WIFEXITED returned true. WIFSIGNALED(status) returns true if the child process was terminated by a signal. WTERMSIG(status) 
 returns the number of the signal that caused the child process to terminate. This macro should only be employed if WIFSIGNALED returned true. 
 返回值:
成功返回子进程的PID, 失败返回-1 
 例如: 回收僵尸态进程资源,并获得子进程退出状态
 int status; wait(&status); 
           仅收尸,不关心子进程退出状态
 wait(NULL);

2.waitpid ()
id_t waitpid(pid_t pid, int *status, int options); 
功能:按指定方式探测子进程状态的改变 R->Z  R->T   T->R  
options 0  WUNTRACED WCONTINUED 

options : WNOHANG waitpid可以非阻塞调用 如果没有子进程状态发生改变,waitpid不阻塞,立即返回,此时返回值为0 

pid 
pid指定为一个特定子进程PID : 只关心指定的子进程状态是否发生改变 
pid指定为-1 : 关心所有的子进程 
pid指定为0 :  关心和父进程同组的子进程 
pid指定为-pid : 关心的是组ID等于|-pid|,组中任意的子进程 

注意: 
 waitpid默认以阻塞方式等待子进程状态变化 
但waitpid也可以非阻塞调用,此时options需要有 WNOHANG, 即如果没有子进程状态发生改变,waitpid不阻塞,立即返回,此时返回值为0
 
 例:与wait(&status);实现相同功能 R->Z 
waitpid(-1,&status,0); 
以非阻塞方式等待进程号为pid1的子进程 
waitpid(pid1,&status,WNOHANG); 
以非阻塞方式等待与父进程同组进程下述三种状态变化 R->Z R->T T->R 
waitpid(0,&status,WNOHANG | WUNTRACED | WCONTINUED);

九、进程的UID

RUID :实际用户ID 进程的创建者 
  EUID : 有效用户ID 决定进程的访问权限 
  SUID : 保存设置ID 保存EUID 

  默认Linux 用户创建的进程:RUID == EUID == SUID 

  注意:如果一个可执行的程序文件,其set-id-bit被打开,此时创建的进程,其EUID等于文件的所有者 普通用户运行程序,

创建进程拥有超级权限 
1.将可执行文件所有者变成root sudo chown root 可执行文件 
2.打开可执行文件的set-id-bit位 sudo chmod u+s 可执行文件名

注意观察下面的命令,更改完成之后,文件的颜色会变成红色。
6.Linux进程线程--进程及相关函数Ⅰ - 戴↑Ω听歌 - ∞
 

十、Linux守护进程
 
Linux下的守护进程daemon 
守护进程有三个最基本的特点:后台运行,独立于终端,完成一定的任务。 

1.首先所谓的后台运行过程是一般是在图形界面或是终端不可见的; 
2.而独立于终端是说它不和终端联系,运行之后一般不接受终端的输入也不向终端输出; 
3.而完成一点的任务是每一个守护进程的运行都是为了完成一定的任务而运行的,这些任务一般都是系统相关的任务。

除开这些特殊性以外,守护进程与普通进程基本上没有什么区别,因此,实际上编写守护进程,可以把一个普通进程按照上述的守护进程的特性改造成为守护进程。  
守护进程必须与其运行前的环境隔离开来。 

这些环境包括未关闭的文件描述符,控制终端,会话和进程组,工作目录以及文件创建掩码等。 这些环境通常是守护进程从执行它的父进程(特别是shell)中继承下来的。 

首先要说几个概念,进程组,会话和控制终端 

进程组:每运行一个程序或是命令就会产生一个进程组,而每一个进程组有一个组长进程. 进程组由进程组号(GID)标识,进程组号(GID)为组长进程PID,一般进程组的第一个进程是组长进程. 组长进程fork的进程也属于同一个进程组,但是子进程一旦执行exec等函数就会不属于该进程组。 

会话:一次登录形成一个会话,一个会话可包含多个进程组(前台或后台), 但只能有一个前台进程组.进程组的集合就是一个会话。 setsid(2)可建立一个新的会话,注意进程组的组长进程不能调用,调用进程是新会话的首进程(session leader) 

控制终端:会话的首进程(session leader)打开一个终端之后, 该终端就成为该会话的控制终端 与控制终端建立连接的会话首进程称为控制进程,一个会话只能有一个控制终端, 在控制终端上产生的输入和信号将发送给会话的前台进程组中的所有进程 终端上的连接断开时 (比如网络断开或 Modem 断开), 挂起信号将发送到控制进程(session leader) 。

6.Linux进程线程--进程及相关函数Ⅰ - 戴↑Ω听歌 - ∞
 

  编程实现守护进程也就是要实现上面的三个特点: 

编写守护进程步骤: 
6.Linux进程线程--进程及相关函数Ⅰ - 戴↑Ω听歌 - ∞
 
(1)创建子进程父进程退出 
(2)子进程创建新会话期(setsid(),调用者不能是组长进程) 
  (3)改变进程工作目录为"/",(chdir("/")) 
(4)重设文件掩码(umask(0)) 
(5)关闭不需要的文件描述符 

  //(1) pid = fork(); if(pid > 0) { exit(); } 
//(2) if(setsid() < 0) { } 
  //(3) chdir("/"); 
  //(4) umask(0); 
  //(5) n = getdtablesize(); 
for(fd = 0;fd < n;fd++) 
 close(fd); 
}

注意:守护进程在运行时需要root权限,让进程拥有超级权限,第九小节。
  评论这张
 
阅读(9)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017