1
嵌入式技术
Linux进程有7种基础状态(两种running算一种),除了traced都可以用$ps命令查看,$ps可以查看的进程状态如下,更多进程状态信息参见Linux Process VS Thread VS LWP
R running or runnable (on run queue)
D uninterruptible sleep (usually IO)
S interruptible sleep (waiting for an event to complete)
T stopped, either by a job control signal or because it is being traced.W paging (not valid since the 2.6.xx kernel)
X dead (should never be seen)
Z defunct ("zombie") process, terminated but not reaped by its parent.
多进程代码区模型(其他区参见copy-on-write):
#include
//getpid() 返回调用进程的PID//getppid() 返回调用进程的父进程的PIDpid_t getpid(void); //pid_t是intpid_t getppid(void);
getuid()返回调用进程的UIDgeteuid()返回调用进程的effective UIDuid_t getuid(void); //uid_t是unsigned intuid_t geteuid(void);
//getgid()返回调用进程的real GID//getegid()返回调用进程的effective GIDid_t getgid(void); //gid_t是unsigned intgid_t getegid(void);
printf("pid=%d\n",getpid()); printf("ppid=%d\n",getppid()); printf("uid=%d\n",getuid()); printf("gid=%d\n",getgid()); }
//创建子进程,在父进程中返回子进程的PID,在子进程中返回0,失败在父进程中返回-1pid_t fork(void);
fork()创建的子进程继承父进程的有:
与父进程有区别的有
fork()产生的所有进程共享代码区,copy-on-write其他区)
fork()一下干的几件事:
//创建任意多个进程:子进程干活,父进程创建一个爹一堆儿子int i=0;for(i=0;i<10;i++){ //创建10个进程, 只有parent在执行for()因为child在每次循环体内就exit()了 pid_t pid=fork(); if(-1==pid) perror("fork"),exit(-1); if(0==pid){ … exit(0); //终止子进程, 自然也就跳出了循环,防止再fork() }}
#include
//创建一个空的子进程,父进程会等待子进程退出之后在继续执行,在子进程执行期间,父进程被挂起,此期间子进程和父进程共享所有的内存资源//vfork()多用在在不拷贝父进程页表的情况下创建新的进程,单独使用没有多线程的价值, 主要和exec()搭配使用。//子进程终止时不能从当前函数返回/调用exit函数, 可以调用_exit(), 该函数保证了子进程先于父进程执行//当下很多系统已经不再支持vfork()函数pid_t vfork(void);
int main(){ pid_t pid=vfork(); if(-1==pid) perror("vfork"),exit(-1); if(0==pid){ printf("child %d starts\n",getpid()); sleep(2); //跳转出去, 调用execl() int res=execl("./proc","proc",NULL); //"ls"表示执行方式, 以字符串的形式传进来 if(-1==res) perror("execl"),_exit(-1);//ATTENTION,用_exit() } printf("parent starts\n"); printf("parent ends\n"); return 0;}//execl()可以跳出当前进程(VS fork()), 去执行一个完全不同的文件,可以帮助vfork()实现多进程,//父进程结束了,系统就会显示[~/Desktop/160512/Code]$,此时发现从已经终结的子进程跳转出的的文件还没执行完, 再打印ls -l的内容$./a.out child 4258 startsparent startsparent ends[~/Desktop/160512/Code]$total 20-rw-rw-r-- 1 tarena tarena 754 5月 12 11:03 01waitpid.c-rw-rw-r-- 1 tarena tarena 449 5月 12 10:31 02vfork.c-rw-rw-r-- 1 tarena tarena 489 5月 12 11:28 03execl.c-rwxrwxr-x 1 tarena tarena 7499 5月 12 11:28 a.out*/
用一个新的进程影像替代当前的进程映像,失败返回-1设errnoextern 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[]);
ATTENTION: vfork()主要与exec family搭配使用, 主要用语子进程执行与父进程完全不同代码段的场合中, 其中vfork()专门用于创建进程, exec family 专门用于跳转执行
, fork()虽然也可以和exec family 搭配使用, 但是fork()会复制父进程的内存空间, 复制完了又跳出去, 没什么意义, 效率不如(vfork(), exec family)
#include
退出状态exit status是我们传入到exit(),_exit(),_Exit()函数的参数。进程正常终止的情况下,内核将退出状态转变为终止状态以供父进程使用wait(),waitpid()等函数获取。终止状态termination status除了上述正常终止进程的情况外,还包括异常终止的情况,如果进程异常终止,那么内核也会用一个指示其异常终止原因的终止状态来表示进程,当然,这种终止状态也可以由父进程的wait(),waitpid()进程捕获。
//引起进程的正常终止,所谓正常终止是按照注册的反顺序依次调用atexit()和on_exit()里注册的函数。VS _exit()和_Exit()会立即终止进程//进程终止后会传递退出码给父进程,这个"退出码&0377"可以被父进程的wait()系列函数捕获并解析。//系统使用8位二进制表示进程退出号,就是0~255,这也是为什么exit()返回status&0377给父进程的原因, 其实是取低八位二进制. 如果exit(10000),实际返回的就是16. void exit(int status);
//注册一个正常终止进程时执行的函数,这个函数的参数必须是void,注册成功返回0,失败返回非0int atexit(void (*function)(void)); //参数是函数指针
//和atexit()类似,用于注册exit()时执行的函数, 不同之处是on_exit注册的函数可以带参数,这个function的两个形参分别是通过exit()传入的int型 和 通过on_exit()传入的*arg//同一个函数可以被多次注册,注册一次退出进程时就会被执行一次//fork()出的子进程会继承父进程的注册函数,但一旦调用了exec(),所有注册的函数都会被移除//成功返回0,失败返回非0int on_exit(void (*function)(int , void *), void *arg);
#include
//立即终止调用的进程,所有的子进程都会挂到PID1下,父进程会收到SIGCHLD信号,还可以用wait()接收退出码void _exit(int status); //
#include
Orphan Process:一个parent退出,而它的一个或多个child还在运行,那么这些child将成为orphan。将被init(PID==1)收养,并由init对它们完成状态收集工作。init会循环地wait()直到这些child完成了他们的工作. 即当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。
Zombie Process: 一个使用fork()创建的child,如果child退出,而parent并没有调用wait/waitpid获取child的状态信息,那么child的process descriptor、PID和PCB等资源仍然保存在系统中。此时的child就变成了zombie。因为系统的PID总数是有限的, parent不断的创建child而不去wait,系统早晚会被拖垮.
总结:
//wait for process to change state//wait()挂起父进程,直到一个子进程结束//waitpid()挂起父进程,直到指定的子进程终止//wait()相当于waitpid(-1, &status, 0)//成功返回子进程的PID,失败返回-1设errnopid_t wait(int *status);pid_t waitpid(pid_t pid, int *status, int options);/* pid in waitpid() and kill() pid>0 //指定pidpid=0 //GID是调用进程PID的子进程pid=-1 //任何子进程pid<-1 //GID是PID的子进程*//*options(Bitwaise Or) WNOHANG //如果没有子进程终止就立即返回return immediately if no child has exited.WUNTRACED //如果一个子进程stoped且没有被traced,那么立即返回WCONTINUED (since Linux 2.6.10) //如果stoped的子进程通过SIGCONT复苏,那么立即返回 *//*如果退出不是NULL,wait()会使用形参指针带出退出码,这个退出码可以使用下列宏解读WIFEXITED(status) //如果子进程正常退出返回真WEXITSTATUS(status) //返回子进程的退出码,当且仅当WIFEXITED为真时有效WIFSIGNALED(status) //如果子进程被一个信号终止时返回真WTERMSIG(status) //返回终止子进程的信号编号,当且仅当WIFSIGNALED为真时有效WCOREDUMP(status) //如果子进程导致了"核心已转储"则返回真,当且仅当WIFSIGNALED为真时有效rWIFSTOPPED(status) //如果子进程被一个信号暂停时返回真,当且仅当调用进程使用WUNTRACED或子进程正在traced时有效WSTOPSIG(status) //返回引起子进程暂停的信号编号,当且仅当WIFSTOPPED为真时有效WIFCONTINUED(status)(since Linux 2.6.10)//如果子进程收到SIGCONT而复苏时返回真*/
if(0==pid){ … exit(100); //把child的退出状态信息设为100}int status=0;int res=wait(&status); //status用来接收结果if(-1==res) perror("wait"),exit(-1);if(WIFEXITED(status)) //ATTENTION:这个宏要int不是int*,和wait不一样 printf("child%d end normally, status is:%d\n",res,WEXITSTATUS(status)); //将打印出exit()里的状态
/*------file.c------*/#include
Note:
/*--------------------------------------------child终止时自动释放malloc()----------------------------------------------*/#include
Note:
/*--------------------------------------------on_exit.c, child终止时自动释放malloc()----------------------------------------------*/#include
全部0条评论
快来发表一下你的评论吧 !