linux程序设计笔记11:进程和信号

1.进程定义:一个其中运行着一个或多个线程的地址空间和这些线程所需要的系统资源。

2.程序代码和系统函数会共享在进程之间,任何时候都在内存中只有一份副本哦。

3.进程号0-32768的整数,当新进程启动了,就自动选下一个没有被分配的PID做为id号。当数字回绕一圈时,新进程就从2开始,1是为init所独有的哦。

4.进程有独立的堆栈空间和独立的环境空间:包含专门为这个进程建立的环境变量。putenv   getenv,还有自己必须维护的程序计数器,用来记录代码执行到了那个位置了。

5.linux中有进程表:用来记录所有的进程信息。PID就是索引。进程表长度是有内存容量限制的,所以系统运行的进程数量也是有上限的。 ps -a all ; ps -f ; full 完整

6.进程状态:S 睡眠 R 运行 D 等待用户输入或输出 T 停止 Z 死进程僵尸 N 低优先级 <高优先级 l 进程是多线程的 s 进程是会话期首进程。 + 进程属于前台进程组 W分页

7.init 进程是:系统第一个进程。可以说是进程管理器。祖先进程。       启动新进程并等待他们结束的能力是整个系统的基础:我们调用fork  exec  wait来完成同样的任务。

8.每个进程轮到的运行时间称之为:时间片。so ,it looks like so match 进程在同时运行。系统内核用进程调度器来决定下一个时间片应该分配给那一个进程。依据优先级。

9.表现良好的程序成为:nice程序。 系统根据进程的nice值来决定他的优先级,一个进程的nice值默认为0,并根据其运行的表现而变化。一般,长期不间断运行的程序,nice值会比较低。而需要等待用户输入的程序系统会增加其nice值。  我们可以使用Nice命令,设置进程nice值,renice命令调整nice值。  ps -l  or -f

      renice 10 pid  ; 调整nice值为0。高优先级的进程总是运行的更频繁,甚至在有些系统中:只要还有高优先级的进程可以运行,那么低优先级的进程根本就不能运行。

10.启动新进程: system()  #include <stdlib.h>   int main(){  begin:    system(" ls -l & "); end; }   其调用shell来启动程序。

        system:其缺点是:程序必须等待由system函数启动的进程结束之后才能继续,因此我们不能立刻执行其他任务。(很少使用system,因为他依赖于shell)

1.exec系类函数:使用exec启动新的程序,原来的程序就不再运行了。 l : 使用可变参数。  v:使用数组。出错返回-1,否则不反悔,因为没了嘛。(替换了都)

 int execl( const char *path , const char *arg0...,(char*) 0);  //直接给定了程序路径。

 int execlp (const char *file , const char *arg0, ... ,(char* ) 0 );  //通过搜索环境路径来找到这个程序  //在系统默认path中去找。

 int execle(const char *path , const char *arg0,... , (char*)0 , char *const envp[] );  //这里最后一个参数是:心程序的环境变量数组。main的隐士最后一个形参呗。

-----------以下和以上一致,只是传递给main的参数使用数组来传递。

 int execv(...)  ;

 int execvp(...);                  char* const ps_argv[]={ "ps", "ax" , 0 };  //参数数组这样设置滴。

 int execve(.....);                   char *const ps_envp[] = { " PATH=/bin:/usr/bin" , "TERM=console" , 0 }; //环境数组这样设置滴。

例子: #include <unistd.h> int main(){  execl( "/bin/ps" ,"ps","ax",0);    }  注意哦,第一个参数依旧是那个程序名称哦,

 

 2.想让进程执行多个函数:我们可以使用多线程、也可以创建一个完全新的进程(fork ,像init的做法一样)。

3.使用fork创建出来的新进程和原来的一模一样,只是具有自己的数据空间等罢了。其执行位置都是一样的。#include <sys/types.h> <unistd.h> pid_t fork();

4.fork出来的新进程,返回值是0,以区别父子进程。  0 是儿子。 失败 返回-1 : 子进程数目达到上限  or  没有了足够的空间来创建进程。

5. #include <sys/types.h>  <unistd.h>  <stdio.h>   main:  pid_t newpid = fork(); switch(newpid) { case -1: error ; break; case 0 : son is me ;break; default : father is me ;break;}        其返回值是:pid_t 类型: <sys/types.h> 中。     我们可以通过sleep(1) 来使进程间切换。

6.wait() 我们可以通过wait() 函数来使一个进程等待另一个进程的结束。#include <sys/wait.h> <sys/types.h>  pid_t wait( int *stat_loc);  返回已经结束的那个进程的pid.

  如果参数 stat_loc不是空指针,那么,该结束的进程的结束状态信息会写入到stat_loc 所指向的内存中:正常结束,非正常结束,等等。。

  错误状态信息:#include <sys/wait.h> 中定义了这些宏。

  WIFEXITED(stat_val) : 如果子进程正常结束,它就取一个非0值。

  WEXITSTATUS(stat_val) : 如果WIFEXITED(stat_val) 非0,它返回子进程的退出码。

 

 WIFSIGNALED(stat_val) : 如果子进程因为一个未捕获的信号而终止,他就取一个非0值。

 WTERMSIG(stat_val) : 如果 WIFSIGNALED(stat_val) 非0,他返回一个信号代码。

 

 WIFSTOPPED(stat_val) : 如果子进程意外终止,他就取一个非0值。

 WSTOPSIG(stat_val) : 如果WIFSTOPPED非0 ,他返回一个信号代码。

我明白了:所谓的等待:就是等那个进程运行结束了,你才结束。 是在调用wait()那一刻。才开始等待,之前不等待。wait()的时候,那个进程是阻塞在那里的。

 有没有子等父这一说呢?wait() 函数是用于父等子的。

就没有 子 等 父 这个说法,子进程不能获取父进程的退出状态。
如果你的意思的是子进程等待父进程执行结束后,再做什么相应处理..
那可以利用某种进程间通信机制,进行通知
 
僵死进程:
 子进程结束了,其依旧会在进程表中,不会立即释放,知道其父进程结束为止。因为他的退出码还需要被别的进程所使用到,以备父进程wait调用。 这时他就是一个僵死进程
一旦父进程发生异常终止,那么该子进程就由init负责接管,在init清理他们之前,他们将一直消耗系统资源。
pid waitpid(pid_t pid, int *stat_loc , int options )  //你可以用它来等待某个特定进程的结束。(依旧是用来等待子进程的结束的。)
 
信号: 是unix/linux系统响应某些条件而产生的一个事件。 信号还可以作为进程间传递消息或修改行为的一种方式。 #include <signal.h>
接收到信号的进程会相应的采取一些行动。   信号是由某些错误条件而生成的:如内存段冲突,浮点处理错误,非法指令等。
常见的:sigint  sigquit sigabort sigalrm sigill  sigterm
如果接收到信号中的一个,但事先没有捕获他,进程将会立即终止。同时系统生存core文件,内存中的映像,对程序调试很有用处。ctrl + c = sigint
 
1.程序中使用:signal() 库函数来处理信号。  int main: signal (SIGINT,abc); while(1){printf"abc";sleep(1);}     void abc(int sig){ printf: sig; signal(SIGINT,SIG_DFL);}
    注意:信号处理函数:1.必须返回值为void  2.必须有且只有一个int sig参数。  //我们不建议使用signal()函数,我们推荐使用:sigaction函数。
 
发送信号:
 我们调用kill() 函数向其他进程包括自己发送信号。 #include <sys/types.h> #include <signal.h>  int kill ( pid_t pid , int sig );
 
类似于闹钟的函数:alarm() 在经过预定时间后发送一个sigalrm信号。 #include <unistd.h>  unsigned int alarm(unisgned int seconds);   seconds秒后发送一条sigalrm信号
:将seconds设置为0,将取消所有已经设置的闹钟请求。
 
2. 挂起一个进程的函数:int pause(void) ;  把程序执行挂起直到一个信号出现为止。 #include <unistd.h>  ,同功能的好方法:sigsuspend()函数。
 
3.使用信号并挂起程序的执行是Linux程序设计中的一个重要部分。
 
sigaction()函数:详见:411页。
信号集:412页
 
 
 
 
 

你可能感兴趣的:(多线程,linux,shell,System,Path,Signal)