- Chen
-
父进程执行到wait的时候,会阻塞等待子进程的结束,一个wait函数只调用一次,如果只有一个wait,其他的子进程在父进程结束后会成为孤儿进程init进程收养。采用不阻塞方式调用waitpid的话,父进程不会等待,没执行完的子进程将会成为孤儿进程
- 小菜G的建站之路
-
1.
父进程只等待任何一个进程状态改变,wait就会立即返回.并携带状态改变的子进程信息.如果需要等待所有进程结束,可以wait外面套循环.
2.
如果子进程结束后父进程才调用wait/waitpid则不会接收到信息.子进程将变成僵尸进程.
相关推荐
进程什么状态wifstopped
进程什么状态wifstoppedwait()函数详细解释: wait(等待子进程中断或结束) 相关函数 waitpid,fork 表头文件 #include #include 定义函数 pid_t wait (int * status); 函数说明 wait()会暂时停止目前进程的执行,直到有信号来到或子进程结 束。如果在调用wait()时子进程已经结束,则wait()会立即返 回子进程结束状态值。子进程的结束状态值会由参数status 返回, 而子进程的进程识别码也会一快返回。如果不在意结束状态值,则 参数status 可以设成NULL。子进程的结束状态值请参考waitpid()。 返回值 如果执行成功则返回子进程识别码(PID),如果有错误发生则返回 -1。失败原因存于errno 中。 附加说明 范例 #include #include #include #include main() { pid_t pid; int status,i; if(fork()= =0){ printf(“This is the child process .pid =%d ”,getpid()); exit(5); }else{ sleep(1); printf(“This is the parent process ,wait for child... ”; pid=wait(&status); i=WEXITSTATUS(status); printf(“child"s pid =%d .exit status=^d ”,pid,i); } } 执行 This is the child process.pid=1501 This is the parent process .wait for child... child"s pid =1501,exit status =5 waitpid(等待子进程中断或结束) 相关函数 wait,fork 表头文件 #include #include 定义函数 pid_t waitpid(pid_t pid,int * status,int options); 函数说明 waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程 结束。如果在调用wait()时子进程已经结束,则wait()会立即 返回子进程结束状态值。子进程的结束状态值会由参数status 返回, 而子进程的进程识别码也会一快返回。如果不在意结束状态值,则 参数status 可以设成NULL。参数pid 为欲等待的子进程识别码, 其他数值意义如下: pid0 等待任何子进程识别码为pid 的子进程。 参数option 可以为0 或下面的OR 组合: WNOHANG 如果没有任何已经结束的子进程则马上返回,不予以 等待。 WUNTRACED 如果子进程进入暂停执行情况则马上返回,但结束 状态不予以理会。 子进程的结束状态返回后存于status,底下有几个宏可判别结束情 况: WIFEXITED(status)如果子进程正常结束则为非0 值。 WEXITSTATUS(status)取得子进程exit()返回的结束代码,一 般会先用WIFEXITED 来判断是否正常结束才能使用此宏。 WIFSIGNALED(status)如果子进程是因为信号而结束则此宏值为 真 WTERMSIG(status) 取得子进程因信号而中止的信号代码,一般 会先用WIFSIGNALED 来判断后才使用此宏。 WIFSTOPPED(status) 如果子进程处于暂停执行情况则此宏值为 真。一般只有使用WUNTRACED 时才会有此情况。 WSTOPSIG(status) 取得引发子进程暂停的信号代码,一般会先 用WIFSTOPPED 来判断后才使用此宏。 返回值 如果执行成功则返回子进程识别码(PID),如果有错误发生则返回 -1。失败原因存于errno 中。 范例 参考wait()。2023-07-17 14:10:551
linux里面的wait和waitpid是什么?
当有多个子进程的SIGCHLD信号到达父进程的时候,如果父进程用wait等待,那么父进程在处理第一个达到的SIGCHLD信号的时候,其他的SIGCHLD信号被堵塞,而且信号不被缓存,这样就会导致信号丢失,这样会产生很多的僵尸进程。。解决办法是父进程用waitpid来等待子进程信号。。。wait 1.1 简介wait函数所需头文件: #include <sys/types.h>#include <sys/wait.h>wait函数原型:pid_t wait(int *status);进程一旦调用了 wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子 进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。 参数status用来保存 被收集进程退出时的一些状态,它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉的毫不在意,只想把这个僵尸进程消灭掉,(事实上绝大多数 情况下,我们都会这样想),我们就可以设定这个参数为NULL,就象下面这样: pid = wait(NULL); 如果成 功,wait会返回被收集的子进程的进程ID,如果调用进程没有子进程,调用就会失败,此时wait返回-1,同时errno被置为ECHILD。 1.2 实战 下面就让我们用一个例子来实战应用一下wait调用,程序中用到了系统调用fork,如果你对此不大熟悉或已经忘记了,请参考fork函数的使用。 /* wait1.c */#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <stdlib.h>int main(){pid_t pc,pr;pc = fork();if (pc < 0) /* 如果出错 */printf("error ocurred! ");else if (pc == 0) /* 如果是子进程 */{ printf("This is child process with pid of %d ",getpid());sleep(10); /* 睡眠10秒钟 */}else /* 如果是父进程 */{ pr = wait(NULL); /* 在这里等待 */printf("I catched a child process with pid of %d "),pr); exit(0);} } 编译并运行: # cc wait1.c -o wait1# ./wait1#This is child process with pid of 1508I #catched a child process with pid of 1508 可以明显注意到,在第2行结果打印出来前有10秒钟的等待时间,这就是我们设定的让子进程睡眠的时间,只有子进程从睡眠中苏醒过来,它才能正常退出,也就才能被父进程捕捉到。其实这里我们不管设定子进程睡眠的时间有多长,父进程都会一直等待下去,读者如果有兴趣的话,可以试着自己修改一下这个数值,看看会出现怎样的结果。 1.3 参数status 如果参数status的值不是NULL,wait就会把子进程退出时的状态取出并存入其中,这是一个整数值(int),指出了子进程是正常退出 还是被非正常结束的(一个进程也可以被其他进程用信号结束),以及正常结束时的返回值,或被哪一个信号结束的等信息。由于这些信息被存放在一个整数的不同二进制位中,所以用常规的方法读取会非常麻烦,人们就设计了一套专门的宏(macro)来完成这项工作,下面我们来学习一下其 中最常用的两个: 1,WIFEXITED(status) 这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个非零值。 (请注意,虽然名字一样,这里的参数status并不同于wait唯一的参数--指向整数的指针status,而是那个指针所指向的整数,切记不要搞混了。) 2,WEXITSTATUS(status) 当WIFEXITED返回非零值时,我们可以用这个宏来提取子进程的返回值,如果子进程调用exit(5)退出,WEXITSTATUS(status)就会返回5;如果子进程调用exit(7),WEXITSTATUS(status)就会返回7。请注意,如果进程不是正常退出的,也就是说,WIFEXITED返回0,这个值就毫无意义。 下面通过例子来实战一下我们刚刚学到的内容: /* wait2.c */#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>int main(){int status;pid_t pc,pr;pc = fork(); /*调用fork函数*/if (pc < 0) /* 如果出错 */printf("error ocurred! ");else if (pc == 0) /* 子进程 */{printf("This is child process with pid of %d. ",getpid());exit(3); /* 子进程返回3 */}else /* 父进程 */{pr = wait(&status);if (WIFEXITED(status)) {printf("the child process %d exit normally. ",pr);printf("the return code is %d. ",WEXITSTATUS(status));}else /* 如果WIFEXITED返回零 */printf("the child process %d exit abnormally. ",pr);}} 编译并运行: # cc wait2.c -o wait2# ./wait2#This is child process with pid of 1538.#the child process 1538 exit normally.#the return code is 3. #the child process 1538 exit abnormally.父进程准确捕捉到了子进程的返回值3,并把它打印了出来。 当然,处理进程退出状态的宏并不止这两个,但它们当中的绝大部分在平时的编程中很少用到,就也不在这里浪费篇幅介绍了,有兴趣的读者可 以自己参阅Linux man pages去了解它们的用法。 waitpid 2.1 简介 waitpid系统调用在Linux函数库中的所需头文件:#include <sys/types.h>#include <sys/wait.h>waitpid系统调用在Linux函数库中的原型是: pid_t waitpid(pid_t pid,int *status,int options);从本质上讲,系统调用waitpid和 wait的作用是完全相同的,但waitpid多出了两个可由用户控制的参数pid和options,从而为我们编程提供了另一种更灵活的方式。下面我们 就来详细介绍一下这两个参数: pid 从参数的名字pid和类型 pid_t中就可以看出,这里需要的是一个进程ID。但当pid取不同的值时,在这里有不同的意义。 pid>0时,等待进程ID等于 pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。 pid=-1时,等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。 pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。 pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。 options options提供了一些额外的选项来控制waitpid,目前在Linux中只支持WNOHANG和WUNTRACED两个选项,这是两个常数,可以用"|"运算符把它们连接起来使用,比如: ret=waitpid(-1,NULL,WNOHANG | WUNTRACED); 如果我们不想使用它们,也可以把options设为0,如: ret=waitpid(-1,NULL,0); 如果使用了 WNOHANG参数调用waitpid,如果没有任何已终止的进程,它也会立即返回,不会像wait那样永远等下去。 而WUNTRACED参数,如果子进程进入暂停执行则马上返回,但终止状态不予理睬。看到这里,聪明的读者可能已经看出端倪了--wait不就是经过包装的waitpid吗?没错,察看<内核源码目录>/include/unistd.h文件349-352行就会发现以下程序段: static inline pid_t wait(int * wait_stat){return waitpid(-1,wait_stat,0);} 2.2 返回值和错误 waitpid的返回值比wait稍微复杂一些,一共有3种情况: 当正常返回的时候,waitpid返回收集到的子进程的进程ID; 如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0; 如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在; 当pid所指示的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid就会出错返回,这时errno被设置为ECHILD; /* waitpid.c */#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>int main(){pid_t pc, pr;pc = fork();if (pc < 0) /* 如果fork出错 */printf("Error occured on forking. ");else if (pc == 0) /* 如果是子进程 */{sleep(10); /* 睡眠10秒 */exit(0);}else /* 如果是父进程 */do{pr = waitpid(pc, NULL, WNOHANG); /* 使用了WNOHANG参数,waitpid不会在这里等待 */if (pr == 0) /* 如果没有收集到子进程 */{ printf("No child exited ");sleep(1);}}while (pr == 0); /* 没有收集到子进程,就回去继续尝试 */if (pr == pc)printf("successfully get child %d ", pr);elseprintf("some error occured ");} 编译并运行: #gcc waitpid.c -o waitpid#./waitpid#No child exited#No child exited#No child exited#No child exited#No child exited#No child exited#No child exited#No child exited#No child exited#No child exited#successfully get child 1526 父进程经过10次失败的尝试之 后,终于收集到了退出的子进程。 因为这只是一个例子程序,不便写得太复杂,所以我们就让父进程和子进程分别睡眠了10秒钟和1秒钟,代表它们分 别作了10秒钟和1秒钟的工作。父子进程都有工作要做,父进程利用工作的简短间歇察看子进程的是否退出,如退出就收集它。2023-07-17 14:11:042
如何获取子进程返回值
调用wait或waitpid有三种不同的情况发生:1、如果其所有子进程都还在运行,则阻塞2、如果一个子进程终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回3、如果它没有任何子进程,则立即出错返回如果进程由于接收到SIGCHLD信号而调用wait,则可期望wait会立即返回,但是如果在任意时刻调用wait,则进程可能会阻塞。在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞。waitpid并不等待在其调用之后的第一个终止子进程,他有若干选项,可以控制他所等待的进程。2023-07-17 14:11:112
Linux 如何使用`wait`等待所有子进程退出,而不是等待第一个子进程退出.希望能给出代码片段?
linux中的wait函数等到一个子进程退出就会返回,恢复到执行状态。要想等所有子进程退出可以用waitpid函数pid_t wait(pid_t pid,int * status,int options);pid>0时,只等待pid与该参数相同的子进程,如果该子进程一直没有退出,那么父进程会一直阻塞;pid=0时,会等待同一个进程组的子进程,若子进程加入了其他进程组,waitpid()不再关心它的状态;pid=-1时,waitpid()与wait()函数相同,将阻塞等待并回收一个子进程;pid<-1时,会等待指定进程组的任何子进程,进程组的id等于pid的绝对值;2023-07-17 14:11:181
linux 中的waitpid函数的返回值问题
-1 是出现错误的返回值,我就不说了。0 只有当你的 waitpid 第三个参数包含 WNOHANG 的时候才有可能。比如pid = fork();if (pid == 0) { //child process while(1) { printf("aaa "); sleep(1); }} else {// parentoption = 0;result = waitpid(pid, NULL, option);。。。。。}上面的代码,由于子进程永远不会结束(除非它被kill),父进程会一直停在 waitpid 那个系统调用,等待子进程结束 (当子进程结束后, waitpid 的返回值等于子进程 pid)。但是如果 option=WNOHANG; 父进程不会停在 waitpid 那里, waitpid 会立刻返回 0 ,表示被等待的子进程并没有结束。2023-07-17 14:11:272
为什么waitpid 返回的是1
WNOHANG 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若结束,则返回该子进程的ID。 raise(SIGSTOP);只不过是让子进程暂停,并没有结束进程。所以返回值为0 还有ret=kill(result,SIGKILL)==0这句实际是这么执行的ret=(kill(r2023-07-17 14:11:331
linux子进程等待父进程
1.父进程只等待任何一个进程状态改变,wait就会立即返回.并携带状态改变的子进程信息.如果需要等待所有进程结束,可以wait外面套循环.2.如果子进程结束后父进程才调用wait/waitpid则不会接收到信息.子进程将变成僵尸进程.2023-07-17 14:11:402
system函数阻塞怎么办
这是进程间同步的问题。解决方法是:fork一个子进程执行system调用,父进程调用 wait 或 waitpid 等待子进程的终止信息。父进程调用 wait 或 waitpid 时可能会:? 阻塞(如果它的所有子进程都还在运行)。? 带子进程的终止信息立即返回(如果一个子进程已终止,正等待父进程读取其终止信息)。? 出错立即返回(如果它没有任何子进程)。wait 和 waitpid 这两个函数的区别是:? 如果父进程的所有子进程都还在运行,调用wait将使父进程阻塞,而调用waitpid时如果在options参数中指定WNOHANG可以使父进程不阻塞而立即返回0。? wait等待第一个终止的子进程,而waitpid可以通过pid参数指定等待哪一个子进程。2023-07-17 14:11:471
软中断通信 在父进程中使用两个wait,它们起什么作用
它是等待任意一个,如果有多个子进程,某一个结束,他就会返回结束的子进程的pid。 如果要等待特定的子进程,可以使用waitpid这个函数2023-07-17 14:11:542
linux 下怎么处理zombie processes
定义In UNIX System terminology, a process that has terminated,but whose parent has not yet waited for it, is called a zombie. 在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他, 那么他将变成一个僵尸进程. 在fork()/execve()过程中,假设子进程结束时父进程仍存在,而父进程fork()之前既没安装SIGCHLD信号处理函数调用 waitpid()等待子进程结束,又没有显式忽略该信号,则子进程成为僵尸进程。如何查看linux系统上的僵尸进程,如何统计有多少僵尸进程?#ps -ef | grep defunct或者查找状态为Z的进程,Z就是代表zombie process,僵尸进程的意思。另外使用top命令查看时有一栏为S,如果状态为Z说明它就是僵尸进程。Tasks: 95 total, 1 running, 94 sleeping, 0 stopped, 0 zombietop命令中也统计了僵尸进程。或者使用下面的命令:ps -ef | grep defunct | grep -v grep | wc -l如何杀死僵尸进程呢?一般僵尸进程很难直接kill掉,不过您可以kill僵尸爸爸。父进程死后,僵尸进程成为”孤儿进程”,过继给1号进程init,init始终会负责清理僵尸进程.它产生的所有僵尸进程也跟着消失。ps -e -o ppid,stat | grep Z | cut -d” ” -f2 | xargs kill -9或kill -HUP `ps -A -ostat,ppid | grep -e "^[Zz]‘ | awk "{print $2}"`当然您可以自己编写更好的shell脚本,欢迎与大家分享。我将nova-novncproxy stop后再start,僵尸进程即消失,问题解决。另外子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行waitpid()函数为子进程收尸。就是基于这样的原理:就算父进程没有调用wait,内核也会向它发送SIGCHLD消息,而此时,尽管对它的默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。如何避免僵尸进程呢?处理SIGCHLD信号并不是必须的。但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在Linux下 可以简单地将 SIGCHLD信号的操作设为SIG_IGN。signal(SIGCHLD,SIG_IGN);这样,内核在子进程结束时不会产生僵尸进程。这一点与BSD4不同,BSD4下必须显式等待子进程结束才能释放僵尸进程或者用两次fork(),而且使紧跟的子进程直接退出,是的孙子进程成为孤儿进程,从而init进程将负责清除这个孤儿进程。2023-07-17 14:12:211
UNIX中system函数的实现为什么要阻塞SIGCHLD信号?
由于system函数的实现基本原理是使用fork函数创建一个子进程,用子进程调用exec函数,之后将子进程运行的内容替换成了目标程序。如果不阻塞SIGCHLD信号,那么如果在调用system函数之前还创建了一个其它的子进程,那么当system函数中fork创建的子进程结束后会给父进程发送SIGCHLD信号,如果此时父进程设置的信号处理方式是捕捉而且在信号处理函数中调用了wait函数,那么system函数就无法根据其函数中创建的子进程返回状态获取相应的返回值。记得有这样的规定,system函数的返回应该是函数中创建子进程的返回状态。所以为了能保证system能够正确获取system函数中创建的子进程返回状态,SIGCHLD信号必须被阻塞。同样,为了保证system函数不出现其它的一些问题,要求system函数要忽略SIGINT和SIGQUIT信号,如果system函数调用的程序是交互式的,如“ed”,就可能出现一些小问题。2023-07-17 14:12:282
w = waitpid(cpid, &status, WUNTRACED | WCONTINUED)是什么意思
慢性盆腔炎,和地位,wuntraced | wcontinued2023-07-17 14:12:362
在linux系统下实现对system() 函数对fork() ,exec(),waitpid()函数的调用。求大神解答
不知道你这实现这些函数的调用是什么意思,是要重写这些接口吗?还是举个例子说明?我解释一下吧:(1)system()其实就是对fork()和exec()函数族等的封装。(2)fork()是用来产生子进程的,是现在我知道的唯一一个返回两个值的函数(有过有另外的,麻烦网友指出),返回-1表示执行失败;否则返回大于0的值时,表示是子进程的进程号,返回0时,表示父进程创建子进程成功。(3)exec()不是一个函数,是函数族,有execl(),execv(),execle(),execve(),execlp(),execvp(),它们常用于子进程中“脱胎换骨”,就是父进程创建子进程后,子进程几乎是父进程的拷贝(只有很少的东西不一样,如进程号(PID)等),然后子进程调用exec()函数族执行其他的程序,即将原来进程的东西全部清除掉,称为一个崭新的进程,所以叫“脱胎换骨”。(4)waitpid()是用在父进程中等待进程退出的,如果父进程不调用这个接口,那么它有可能先于子进程退出,那么子进程就会称为孤儿进程,继而被init进程(PID为1的进程,Linux启动后第一个启动的进程)收养。或者父进程并未退出,也未调用这个接口,但是子进程已经执行完成,那么子进程就会成为一个僵尸进程。具体例子在网上找找吧,都不是很难。2023-07-17 14:12:431
OS.WNOHANG 是什么意思?
那是一个os模块的常量,一般在os.waitpid(-1 , os.WNOHANG)里面用-1 表示等待所有的子进程结束,作用相当于调用wait ,WNOHANG表示不使父进程挂起,而立即返回2023-07-17 14:12:501
sleep和wait有什么区别
sleep和wait的区别是词性不同,sieep是动词,wait是形容词。1、sleepsleep是一个英语单词,意思是睡觉,也可以作为延伸意义使用,即死亡、长眠的意思。是一个不及物动词,也可用作及物动词,意为“可供...住宿”,但不常用。Sleep相关短语leep in 住在雇主家里。sleep on/upon/over a problem 把问题留到第二天解决。sleep with one"s fathers 葬在祖墓,死了。get to sleep 睡着。not sleep a wink 无法成眠。2、waitwait英语中有等待的意思,在计算机领域它还是一种Java术语,C语言中也有wait命令。一个参数的wait方法,但它允许更好地控制在放弃之前等待通知的时间量。用毫微秒度量的实际时间量可以通过以下公式计算出来:1000000*timeout+nanos在其他所有方面,此方法执行的操作与带有一个参数的wait、long方法相同。需要特别指出的是,wait与wait相同。wait也有等待子进程中断或结束的含义,相关函数为waitpid,fork。Wait相关习惯用语at in wait等待、lie in wait for 埋伏着等待,准备出其不意地袭击或恐吓、Everything comes to him who waits,凡事都要肯等,久等必有一善。wait a bit 等一下,稍等一等;wait and see等着瞧吧,等等看;wait at table 侍候人家吃饭。wait for、waitup等待,等候;wait out 在外面等着等到末了,以等待的方式挫败。wait until、wait till等到。wait up、wait for熬夜等候。wait upon 服侍,招待;追随;拜访;随着而产生。2023-07-17 14:12:571
下面是我在linux下写的守护进程,现在想收到SIGUSR1的信号后跳出while循环,该怎么写
守护进程只知道过程,没具体实现过,但我想了想,你可以设置一个变量,给变量一个初值比如count = 1;然后while(count),然后你收到SIGUSR1后去执行特定函数,把count置零,这样就可以实现。 然后再一个if语句,判count是否为0,为0就break,这样就达到目的了,俺不是牛人,就想到了这个办法,有好办法分享一下哈。。。2023-07-17 14:13:191
子进程中如何获得system执行的PID
记得某unix教程上说的system(2)函数也是fork(2)和execl*(2)的组合(也许是我想当然了,但确实能这样实现)。也就是说system是在子进程中执行的,等同于if (fork() == 0) {execl*()}了,子进程的状态,当然可以通过waitpid来得到。2023-07-17 14:13:261
Linux中的defunct进程(僵尸进程)
一、什么是defunct进程(僵尸进程)? 在 Linux 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他,那么他将变成一个僵尸进程。当用ps命令观察进程的执行状态时,看到这些进程的状态栏为defunct。僵尸进程是一个早已死亡的进程,但在进程表(processs table)中仍占了一个位置(slot)。 但是如果该进程的父进程已经先结束了,那么该进程就不会变成僵尸进程。因为每个进程结束的时候,系统都会扫描当前系统中所运行的所有进程,看看有没有哪个进程是刚刚结束的这个进程的子进程,如果是的话,就由Init进程来接管他,成为他的父进程,从而保证每个进程都会有一个父进程。而Init进程会自动wait其子进程,因此被Init接管的所有进程都不会变成僵尸进程。 二、 Linux下进程的运作方式 如果子进程先于父进程退出, 同时父进程又没有调用wait/waitpid,则该子进程将成为僵尸进程。如果该进程的父进程已经先结束了,那么该进程就不会变成僵尸进程。因为每个进程结束的时候,系统都会扫描当前系统中所运行的所有进程,看看有没有哪个 进程是刚刚结束的这个进程的子进程,如果是的话,就由Init进程来接管他,成为他的父进程,从而保证每个进程都会有一个父进程。而Init进程会自动 wait其子进程,因此被Init接管的所有进程都不会变成僵尸进程。 每个 Linux进程在进程表里都有一个进入点(entry),核心进程执行该进程时使用到的一切信息都存储在进入点。当用 ps 命令察看系统中的进程信息时,看到的就是进程表中的相关数据。当以fork()系统调用建立一个新的进程后,核心进程就会在进程表中给这个新进程分配一个进入点,然后将相关信息存储在该进入点所对应的进程表内。这些信息中有一项是其父进程的识别码。 子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程到底什么时候结束。那么会不会因为父进程太忙来不及 wait 子进程,或者说不知道子进程什么时候结束,而丢失子进程结束时的状态信息呢? 不会。因为 Linux提供了一种机制可以保证,只要父进程想知道子进程结束时的状态信息,就可以得到。这种机制就是:当子进程走完了自己的生命周期后,它会执行exit()系统调用,内核释放该进程所有的资源,包括打开的文件,占用的内存等。但是仍然为其保留一定的信息(包括进程号the process ID,退出码exit code,退出状态the terminationstatus of the process,运行时间the amount of CPU time taken by the process等),这些数据会一直保留到系统将它传递给它的父进程为止,直到父进程通过wait / waitpid来取时才释放。 也就是说,当一个进程死亡时,它并不是完全的消失了。进程终止,它不再运行,但是还有一些残留的数据等待父进程收回。当父进程 fork() 一个子进程后,它必须用 wait() (或者 waitpid())等待子进程退出。正是这个 wait() 动作来让子进程的残留数据消失。 三、僵尸进程的危害 如果父进程不调用wait / waitpid的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统的进程表容量是有限的,所能使用的进程号也是有限的,如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程。 所以,defunct进程不仅占用系统的内存资源,影响系统的性能,而且如果其数目太多,还会导致系统瘫痪。而且,由于调度程序无法选中Defunct 进程,所以不能用kill命令删除Defunct 进程,惟一的方法只有重启系统。 四、如何杀死defunct进程 defunct进程是指出错损坏的进程,父子进程之间不会再通信。有时,它们会演变成“僵尸进程”,存留在你的系统中,直到系统重启。可以尝试 “kill -9” 命令来清除,但多数时候不管用。 为了杀死这些defunct进程,你有两个选择: 1.重启你的计算机 2.继续往下读… 我们先看看系统中是否存在defunct进程: $ ps -A|grep defunct 1 输出 5259 ? 00:00:00 sd_cicero <defunct> 12214 pts/18 00:01:14 python <defunct> 16989 pts/18 00:04:43 python <defunct> 20610 pts/18 00:23:12 python <defunct> 看看这些进程的ID及其父进程ID: $ ps -ef | grep defunct | more UID PID PPID ... ========================================================================== yourname 4653 6128 0 17:07 pts/18 00:00:00 grep --color=auto defunct yourname 5259 5258 0 15:58 ? 00:00:00 [sd_cicero] <defunct> yourname 12214 12211 4 16:41 pts/18 00:01:14 [python] <defunct> yourname 16989 16986 20 16:45 pts/18 00:04:43 [python] <defunct> yourname 20610 18940 99 16:48 pts/18 00:23:12 [python] <defunct> UID:用户ID PID:进程ID PPID:父进程ID 如果你使用命令 “kill -9 12214” 尝试杀死ID为12214的进程,可能会没效果。 我们来试一下 ps -A|grep defunct 输出 5259 ? 00:00:00 sd_cicero <defunct> 12214 pts/18 00:01:14 python <defunct> 16989 pts/18 00:04:43 python <defunct> 20610 pts/18 00:23:12 python <defunct> 进程12214 仍然存才,说明用kill杀不掉它。 要想成功杀死该进程,需要对其父进程(ID为12211)执行kill命令( ps -A | grep defunct)。 我们来试一下 ps -A|grep defunct 输出 5259 ? 00:00:00 sd_cicero <defunct> 16989 pts/18 00:04:43 python <defunct> 20610 pts/18 00:23:12 python <defunct> [1] Killed bash main.sh 进程12214消失,说明可以通过kill僵尸进程的父进程来杀死僵尸进程。 如果前一个命令显示无结果,那么搞定!否则,可能你需要重启一下系统。 参考链接: https://www.cnblogs.com/lfxiao/p/10837115.html2023-07-17 14:13:331
WEXITSTATUS这个函数是做什么的?
WEXITSTATUS是一个检验子进程退出的正常还是非正常和返回值的宏WIFEXITED(status) 这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个非零值。WEXITSTATUS(status) 当WIFEXITED返回非零值时,可以用这个宏来提取子进程的返回值,如果子进程调用exit(5)退出,WEXITSTATUS(status)就会返回5;如果子进程调用exit(7),WEXITSTATUS(status)就会返回7。请注意,如果进程不是正常退出的,也就是说,WIFEXITED返回0,这个值就毫无意义。扩展资料:子进程的结束状态返回后存于 status,底下有几个宏可判别结束情况:WIFEXITED(status)如果若为正常结束子进程返回的状态,则为真;对于这种情况可执行WEXITSTATUS(status),取子进程传给exit或_eixt的低8位。WEXITSTATUS(status)取得子进程 exit()返回的结束代码,一般会先用 WIFEXITED 来判断是否正常结束才能使用此宏。参考资料:百度百科-waitpid2023-07-17 14:13:532
串口为什么自动打印数据
、去掉printk打印在linux内核中的/kernel目录下printk.c文件中有一个函数:static void __call_console_drivers(unsigned long start, unsigned long end){struct console *con;for (con = console_drivers; con; con = con->next) {if ((con->flags & CON_ENABLED) && con->write)con->write(con, &LOG_BUF(start), end - start);}}去掉如下两行重新编译内核即可:if ((con->flags & CON_ENABLED) && con->write)con->write(con, &LOG_BUF(start), end - start);2、标准输出、标准错误输出重定向int main() {int pid = 0;// fork a worker processif (pid = fork()) {// wait for completion of the child processint status;waitpid(pid, &status, 0);}else {// open /dev/nullint fd_null = open("/dev/null",O_RDWR);if(dup2(fd_null, 1) == -1)return 1;if(dup2(fd_null, 2) == -1)return 1;XX_run();}return 0;}我将标准输出和错误输出重定向到/dev/null中如果我没有将输出重定向,只是关闭输出,close(1) close(2),程序经常出现错误,这个还需要继续研究。2023-07-17 14:14:121
c语言指令有哪些啊
第一章:绪论?内核版本号格式:x.y.zz-www/x为主版本号,y为次版本号,zz为次次版本号,www为发行号/次版本号改变说明内核有重大变革,其偶数为稳定版本,奇数为尚在开发中的版本 第二章:基础?文件种类:-:txt,二进制/d:目录/l:链接文件(link)/b:区块设备文件/c:字符设备文件/p:管道目录结构:bin:可执行/boot:开机引导/dev:设备文件/etc:系统配置文件/lib:库文件/mnt:设备挂载点/var:系统日志/命令:rmdir:删除空目录/find [path] [expression]/touch命令还可以修改指定文件的最近一次访问时间/tar -czvf usr.tar.gz path/tar –zxvf usr.tar.gz/tar –cjvf usr.tar.bz2 path/tar –jxvf usr.tar.bz2gcc:预处理:-g/I在头文件搜索路径中添加目录,L在库文件搜索路径中gdb:设置断点:b/查看断点信息:infoMakefile:make –f other_makefile/<:第一个依赖文件的名称/@:目标文件的完整名称/^:所有不重复的依赖文件/+:所有依赖文件(可能重复) 第三章:文件IOread:read(fd, temp, size); /读fd中长度为size的值到temp/返回0表示file为NULLwrite:write(fd, buf, buf_size); /写长度为buf_size的buf内容到fd中lseek:lseek(fd, offset, SEEK_SET); /从文件开头向后增加offset个位移量unlink:从文件系统中删除一个名字open1:int open(const char * pathname, int flags, mode_t mode);/flags为读写方式/mode为权限设置/O_EXCL:测试文件是否存在/O_TRUNC:若存在同名文件则删除之并新建open2:注意O_NONBLOCKmmap.1:void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offsize);mmap.2:mmap(start_addr, flength, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);fcntl:上锁/int fcntl(int fd, int cmd, struct flock * lock);/对谁;做什么;设置所做内容select:fd_max+1,回传读状况,回传写状况,回传异常,select等待的时间/NULL为永远等待/0为从不等待/凡需某状况则用之,反则(fd_set *)NULL之FD_*那几个函数……一般出错则返回-1 第四章:文件与目录硬链接与符号链接?chdir改变目录0:in/1:out/2:err 第五章:内存管理可执行文件存储时:代码区、数据区和未初始化区栈:by编译器,向低址扩展,连续,效率高/堆:by程序员/etc/syslog.conf,系统log记录文件/优先级为-20时最高 第六章:进程和信号程序代码、数据、变量、文件描述符和环境/init的pid为1execl族:int execl(const char * path, const char * arg, ....);/path即可执行文件的路径,一般为./最后一个参数以NULL结束waitpid:waitpid(pid_t pid,int * status,int options);/option:一般用WNOHANG,没有已经结束的子进程则马上返回,不等待kill:int kill(pid_t pid,int sig);/发送信号sig给pidvoid (*signal(int signum, void(* handler)(int)))(int);/第一个参数被满足时,执行handler/第一个参数常用:SIG_IGN:忽略信号/SIG_DFL:恢复默认信号 第七章:线程sem_init(sem_t *sem, int pshared, unsigned int value)/pshared为0/value即初始值 第八章:管道1:write/0:read 第九章:信号量、共享内存和消息队列临界资源:操作系统中只允许一个进程访问的资源/临界区:访问临界资源的那段代码信号量:建立联系(semget),然后初始化,PV操作,最后destroy共享内存没有提供同步机制 第十章:套接字UDP:无连接协议,无主客端的区分/实时性TCP:字节流/数据可靠性/网络可靠性数据报:SOCK_STREAM/SOCK_DGRAM 其它管道一章的both_pipe即父子进程间的全双工管道通讯关系到信号和互斥的服务器-客户端程序线程一章的class的multi_thread文件夹下的thread8.c int main(void){ int data_processed; int file_pipes_1[2]; int file_pipes_2[2]; char buffer[BUFSIZ + 1]; const char some_data[] = "123"; const char ch2p[] = "this is the string from child to the parent!"; const char p2ch[] = "this is the string from parent to the child!"; pid_t fork_result; memset(buffer,"",sizeof(buffer)); if(pipe(file_pipes_1) == 0){ if(pipe(file_pipes_2) == 0){ fork_result = fork(); switch(fork_result){ case -1: perror("fork error"); exit(EXIT_FAILURE); case 0://child close(file_pipes_1[1]); close(file_pipes_2[0]); printf("in the child! "); read(file_pipes_1[0],buffer, BUFSIZ); printf("in the child, read_result is "%s" ",buffer); write(file_pipes_2[1],ch2p, sizeof(ch2p)); printf("in the child, write_result is "%s" ",ch2p); exit(EXIT_SUCCESS); default://parent close(file_pipes_1[0]); close(file_pipes_2[1]); printf("in the parent! "); write(file_pipes_1[1], p2ch, sizeof(p2ch)); printf("in the parent, write_result is "%s" ",p2ch); read(file_pipes_2[0],buffer, BUFSIZ); printf("in the parent, read_result is "%s" ",buffer); exit(EXIT_SUCCESS); } } }} #ifndef DBG#define DBG#endif #undef DBG#ifdef DBG#define PRINTF(fmt, args...) printf("file->%s line->%d: " fmt, __FILE__, __LINE__, ##args)#else#define PRINTF(fmt, args...) do{}while(0);#endif int main(void){ PRINTF("%s ", "hello!"); fprintf(stdout, "hello hust! "); return 0;} #define N 5#define MAX 5 int nput = 0;char buf[MAX][50];char *buffer = "abcdefghijklmnopqrstuvwxyz0123456789";char buf_r[100];sem_t mutex,full,avail; void *productor(void *arg);void *consumer(void *arg);int i = 0; int main(int argc, char **argv){ int cnt = -1; int ret; int nput = 0; pthread_t id_produce[10]; pthread_t id_consume; ret = sem_init(&mutex, 0, 1); ret = sem_init(&avail, 0, N); ret = sem_init(&full, 0, 0); for(cnt = 0; cnt < 6; cnt ++ ){ //pthread_create(&id_produce[cnt], NULL, (void *)productor, &cnt); pthread_create(&id_produce[cnt], NULL, (void *)productor, (void *)cnt); } pthread_create(&id_consume, NULL, (void *)consumer, NULL); for(cnt = 0; cnt < 6; cnt ++){ pthread_join(id_produce[cnt], NULL); } pthread_join(id_consume,NULL); sem_destroy(&mutex); sem_destroy(&avail); sem_destroy(&full); exit(EXIT_SUCCESS);}void *productor(void *arg){ while(1){ sem_wait(&avail); sem_wait(&mutex); if(nput >= MAX * 3){ sem_post(&avail); //sem_post(&full); sem_post(&mutex); return NULL; } sscanf(buffer + nput, "%s", buf[nput % MAX]); //printf("write[%d] "%s" to the buffer[%d] ", (*(int*)arg), buf[nput % MAX],nput % MAX); printf("write[%d] "%s" to the buffer[%d] ", (int)arg, buf[nput % MAX],nput % MAX); nput ++; printf("nput = %d ", nput); sem_post(&mutex); sem_post(&full); } return NULL;} void *consumer(void *arg){ int nolock = 0; int ret, nread, i; for(i = 0; i < MAX * 3; i++) { sem_wait(&full); sem_wait(&mutex); memset(buf_r, 0, sizeof(buf_r)); strncpy(buf_r, buf[i % MAX], sizeof(buf[i % MAX])); printf("read "%s" from the buffer[%d] ",buf_r, i % MAX); sem_post(&mutex); sem_post(&avail); //sleep(1); } return NULL;}2023-07-17 14:14:315
在system函数里执行ls,怎么把ls的结果printf
linux c system函数介绍:system(执行shell 命令)相关函数fork,execve,waitpid,popen表头文件#i nclude定义函数int system(const char * string);函数说明system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命>令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。返回值=-1:出现错误 =0:调用成功但是没有出现子进程 >0:成功退出的子进程的id如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1。若参数string为空指针(NULL),则返回非零值>。如果system()调用成功则最后会返回执行shell命令后的返回值,但是此返回值也有可能为 system()调用/bin/sh失败所返回的127,因此最好能再检查errno 来确认执行成功。附加说明在编写具有SUID/SGID权限的程序时请勿使用system(),system()会继承环境变量,通过环境变量可能会造成系统安全的问题。范例#i ncludemain(){system("ls -al /etc/passwd /etc/shadow");}执行结果:-rw-r--r-- 1 root root 705 Sep 3 13 :52 /etc/passwd-r--------- 1 root root 572 Sep 2 15 :34 /etc/shado例2:char tmp[];sprintf(tmp,"/bin/mount -t vfat %s /mnt/usb",dev);system(tmp);其中dev是/dev/sda1。 system函数的源码#include <syspes.h>#include <sys/wait.h>#include <errno.h>#include <unistd.h>int system(const char * cmdstring){pid_t pid;int status;if(cmdstring == NULL){return (1);}if((pid = fork())<0){status = -1;}else if(pid = 0){execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);-exit(127); //子进程正常执行则不会执行此语句}else{while(waitpid(pid, status, 0) < 0){if(errno != EINTER){status = -1;break;}}}return status;}那么如何获得system的返回值呢??char buf[10];char * ps="ps -ef|grep -c root";FILE *ptr;int i;if((ptr = popen(ps, "r")) != NULL){fgets(buf, 10 , ptr);i = atoi(buf);pclose(ptr);}可以man下waitpid查看下如何检查status的值 int ret = system("ls -al /etc/passwd /etc/shadow");if(WIFSIGNALED(ret))具体的这些宏查看man waitpid2023-07-17 14:14:471
在Linux中,用fork函数产生一个新的子进程,子进程结束后,子进程就成为了僵尸进程?
僵尸进程的避免⒈父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起。⒉ 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后, 父进程会收到该信号,可以在handler中调用wait回收。⒊ 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD,SIG_IGN) 通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收, 并不再给父进程发送信号。⒋ 还有一些技巧,就是fork两次,父进程fork一个子进程,然后继续工作,子进程fork一 个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收 还要自己做。2023-07-17 14:14:561
Linux启动新进程的几种方法及比较
有时候,我们需要在自己的程序(进程)中启动另一个程序(进程)来帮助我们完成一些工作,那么我们需要怎么才能在自己的进程中启动其他的进程呢?在Linux中提供了不少的方法来实现这一点,下面就来介绍一个这些方法及它们之间的区别。一、system函数调用 system函数的原型为: #include int system (const char *string);它的作用是,运行以字符串参数的形式传递给它的命令并等待该命令的完成。命令的执行情况就如同在shell中执行命令:sh -c string。如果无法启动shell来运行这个命令,system函数返回错误代码127;如果是其他错误,则返回-1。否则,system函数将返回该命令的退出码。 注意:system函数调用用一个shell来启动想要执行的程序,所以可以把这个程序放到后台中执行,这里system函数调用会立即返回。 可以先先下面的例子,源文件为new_ps_system.c,代码如下: #include #include int main() { printf("Running ps with system "); //ps进程结束后才返回,才能继续执行下面的代码 system("ps au");// 1 printf("ps Done "); exit(0); }该程序调用ps程序打印所有与本用户有关的进程,最后才打印ps Done。运行结果如下: 如果把注释1的语句改为:system("ps au &");则system函数立即返回,不用等待ps进程结束即可执行下面的代码。所以你看到的输出,ps Done可能并不是出现在最后一行,而是在中间。 一般来说,使用system函数不是启动其他进程的理想手段,因为它必须用一个shell来启动需要的程序,即在启动程序之前需要先启动一个shell,而且对shell的环境的依赖也很大,因此使用system函数的效率不高。 二、替换进程映像——使用exec系列函数 exec系列函数由一组相关的函数组成,它们在进程的启动方式和程序参数的表达方式上各有不同。但是exec系列函数都有一个共同的工作方式,就是把当前进程替换为一个新进程,也就是说你可以使用exec函数将程序的执行从一个程序切换到另一个程序,在新的程序启动后,原来的程序就不再执行了,新进程由path或file参数指定。exec函数比system函数更有效。 exec系列函数的类型为: #include char **environ; int execl (const char *path, const char *arg0, ..., (char*)0); int execlp(const char *file, const char *arg0, ..., (char*)0); int execle(const char *path, const char *arg0, ..., (char*)0, char *const envp[]); int execv (const char *path, char *const argv[]); int execvp(cosnt char *file, char *const argv[]); int execve(const char *path, char *const argv[], char *const envp[]);这类函数可以分为两大类,execl、execlp和execle的参数是可变的,以一个空指针结束,而execv、execvp和execve的第二个参数是一个字符串数组,在调用新进程时,argv作为新进程的main函数的参数。而envp可作为新进程的环境变量,传递给新的进程,从而变量它可用的环境变量。 承接上一个例子,如果想用exec系统函数来启动ps进程,则这6个不同的函数的调用语句为: 注:arg0为程序的名字,所以在这个例子中全为ps。 char *const ps_envp[] = {"PATH=/bin:usr/bin", "TERM=console", 0}; char *const ps_argv[] = {"ps", "au", 0}; execl("/bin/ps", "ps", "au", 0); execlp("ps", "ps", "au", 0); execle("/bin/ps", "ps", "au", 0, ps_envp); execv("/bin/ps", ps_argv); execvp("ps", ps_argv); execve("/bin/ps", ps_argv, ps_envp);下面我给出一个完整的例子,源文件名为new_ps_exec.c,代码如下: #include #include #include int main() { printf("Running ps with execlp "); execlp("ps", "ps", "au", (char*)0); printf("ps Done"); exit(0); }运行结果如下: 细心的话,可以发现,最后的ps Done并没有输出,这是偶然吗?并不是,因为我们并没有再一次返回到程序new_ps_exec.exe上,因为调用execlp函数时,new_ps_exec.exe进程被替换为ps进程,当ps进程结束后,整个程序就结束了,并没有回到原来的new_ps_exec.exe进程上,原本的进程new_ps_exec.exe不会再执行,所以语句printf("ps Done");根本没有机会执行。 注意,一般情况下,exec函数是不会返回的,除非发生错误返回-1,由exec启动的新进程继承了原进程的许多特性,在原进程中已打开的文件描述符在新进程中仍将保持打开,但任何在原进程中已打开的目录流都将在新进程中被关闭。 三、复制进程映像——fork函数1、fork函数的应用 exec调用用新的进程替换当前执行的进程,而我们也可以用fork来复制一个新的进程,新的进程几乎与原进程一模一样,执行的代码也完全相同,但新进程有自己的数据空间、环境和文件描述符。 fork函数的原型为: #include #include pid_t fork();注:在父进程中,fork返回的是新的子进程的PID,子进程中的fork返回的是0,我们可以通过这一点来判断父进程和子进程,如果fork调用失败,它返回-1. 继承上面的例子,下面我给出一个调用ps的例子,源文件名为new_ps_fork.c,代码如下: #include #include #include #include int main() { pid_t pid = fork(); switch(pid) { case -1: perror("fork failed"); exit(1); break; case 0: //这是在子进程中,调用execlp切换为ps进程 printf(" "); execlp("ps", "ps", "au", 0); break; default: //这是在父进程中,输出相关提示信息 printf("Parent, ps Done "); break; } exit(0); }输出结果为: 我们可以看到,之前在第二点中没有出现的ps Done是打印出来了,但是顺序却有点不对,这是因为,父进程先于子程序执行,所以先输出了Parent, ps Done,那有没有办法让它在子进程输出完之后再输出,当然有,就是用wait和waitpid函数。注意,一般情况下,父进程与子进程的生命周期是没有关系的,即便父进程退出了,子进程仍然可以正常运行。 2、等待一个进程 wait函数和waitpid函数的原型为: #include #include pid_t wait(int *stat_loc); pid_t waitpid(pid_t pid, int *stat_loc, int options);wait用于在父进程中调用,让父进程暂停执行等待子进程的结束,返回子进程的PID,如果stat_loc不是空指针,状态信息将被写入stat_loc指向的位置。 waitpid等待进程id为pid的子进程的结束(pid为-1,将返回任一子进程的信息),stat_loc参数的作用与wait函数相同,options用于改变waitpid的行为,其中有一个很重要的选项WNOHANG,它的作用是防止waippid调用者的执行挂起。如果子进程没有结束或意外终止,它返回0,否则返回子进程的pid。 改变后的程序保存为源文件new_ps_fork2.c,代码如下: #include #include #include #include int main() { pid_t pid = fork(); int stat = 0; switch(pid) { case -1: perror("fork failed"); exit(1); break; case 0: //这是在子进程中,调用execlp切换为ps进程 printf(" "); execlp("ps", "ps", "au", 0); break; default: //这是在父进程中,等待子进程结束并输出相关提示信息 pid = wait(&stat); printf("Child has finished: PID = %d ", pid); //检查子进程的退出状态 if(WIFEXITED(stat)) printf("Child exited with code %d ", WEXITSTATUS(stat)); else printf("Child terminated abnormally "); printf("Parent, ps Done "); break; } exit(0); }输出为: 可以看到这次的输出终于正常了,Parent的输出也在子进程的输出之后。 总结——三种启动新进程方法的比较 首先是最简单的system函数,它需要启动新的shell并在新的shell是执行子进程,所以对环境的依赖较大,而且效率也不高。同时system函数要等待子进程的返回才能执行下面的语句。 exec系统函数是用新的进程来替换原先的进程,效率较高,但是它不会返回到原先的进程,也就是说在exec函数后面的所以代码都不会被执行,除非exec调用失败。然而exec启动的新进程继承了原进程的许多特性,在原进程中已打开的文件描述符在新进程中仍将保持打开,但需要注意,任何在原进程中已打开的目录流都将在新进程中被关闭。 fork则是用当前的进程来复制出一个新的进程,新进程与原进程一模一样,执行的代码也完全相同,但新进程有自己的数据空间、环境变量和文件描述符,我们通常根据fork函数的返回值来确定当前的进程是子进程还是父进程,即它并不像exec那样并不返回,而是返回一个pid_t的值用于判断,我们还可以继续执行fork后面的代码。2023-07-17 14:15:031
一个c语言execlp函数问题
execlp函数是没有问题的,出现这种现象的原因在于child2=fork();这个语句的位置不对,你把它移到if(child2<0)的前面就不会出现这种问题 详细的原因,我写到空间里面了:http://hi.baidu.com/y0315219/blog/item/fb412f10be6212efc2ce792a.html2023-07-17 14:15:101
简单的shell编程
#include <unistd.h>#include <sys/types.h>#include <sys/wait.h>#include <stdlib.h>#include <sys/stat.h>#include <fcntl.h>#define BUFFERSIZE 80extern char *get_current_dir_name(void);extern char *getenv(const char *name);extern pid_t waitpid(pid_t pid, int *status, int options);char buffer[BUFFERSIZE+1];main(){ char *path, *arg[10], *input; int li_inputlen, is_bj, is_back, i, j, k, pid, status; char lc_char; while (1){ /* initiations */ is_bj = 0; /*redirection flag*/ is_back = 0; /*background*/ /* shell prompt */ path = get_current_dir_name(); printf("%s>$",path); /*开始获取输入*/ li_inputlen = 0; lc_char = getchar(); while (lc_char !=" "){ if(li_inputlen < BUFFERSIZE) buffer[li_inputlen++] = lc_char; lc_char = getchar(); } /*命令超长处理*/ if (li_inputlen >= BUFFERSIZE){ printf("Your command is too long! Please re-enter your command! "); li_inputlen = 0; /*reset */ continue; } else buffer[li_inputlen] = "";/*加上串结束符号,形成字串*/ /*将命令从缓存拷贝到input中*/ input = (char *) malloc(sizeof(char) * (li_inputlen+1)); strcpy(input,buffer);/* 获取命令和参数并保存在arg中*/ for (i = 0,j = 0,k = 0;i <= li_inputlen;i++){ /*管道和重定向单独处理*/ if (input[i] == "<" || input[i] == ">" || input[i] =="|"){ if (input[i] == "|") pipel(input,li_inputlen); else redirect(input,li_inputlen); is_bj = 1; break; } /*处理空格、TAB和结束符。不用处理‘ ",大家如果仔细分析前面的获取输入的程序的话, *不难发现回车符并没有写入buffer*/ if (input[i] == " " || input[i] ==" " || input[i] == ""){ if (j == 0) /*这个条件可以略去连在一起的多个空格或者tab*/ continue; else{ buffer[j++] = ""; arg[k] = (char *) malloc(sizeof(char)*j); /*将指令或参数从缓存拷贝到arg中*/ strcpy(arg[k],buffer); j = 0; /*准备取下一个参数*/ k++; } } else{ /*如果字串最后是‘&",则置后台运行标记为1*/ if (input[i] == "&" && input[i+1] == ""){ is_back = 1; continue; } buffer[j++] = input[i]; } } free(input);/*释放空间*//*如果输入的指令是leave则退出while,即退出程序*/ if (strcmp(arg[0],"leave") == 0 ){ printf("bye-bye "); break; } /*如果输入的指令是about则显示作者信息,同时结束本条命令的解析过程*/ if (strcmp(arg[0]," about") == 0 ){ printf("copyright by shike,shike13@163.com "); continue; } if (is_bj == 0){ /*非管道、重定向指令*//*在使用xxec执行命令的时候,最后的参数必须是NULL指针, *所以将最后一个参数置成空值*/ arg[k] = (char *) 0; /*判断指令arg[0]是否存在*/ if (is_fileexist(arg[0]) == -1 ){ printf("This command is not found?! "); for(i=0;i<k;i++) free(arg[i]); continue; } /* fork a sub-process to run the execution file */ if ((pid = fork()) ==0) /*子进程*/ execv(buffer,arg); else /*父进程*/ if (is_back == 0) /*并非后台执行指令*/ waitpid(pid,&status,0); /*释放申请的空间*/ for (i=0;i<k;i++) free(arg[i]); } }}int is_fileexist(char *comm){ char *path,*p; int i; i = 0;/*使用getenv函数来获取系统环境变量,用参数PATH表示获取路径*/ path = getenv("PATH"); p = path; while (*p != ""){ /*路径列表使用‘:"来分隔路径*/ if (*p != ":") buffer[i++] = *p; else{ buffer[i++] = "/"; buffer[i] = "";/*将指令和路径合成,形成pathname,并使用access函数来判断该文件是否存在*/ strcat(buffer,comm); if (access(buffer,F_OK) == 0) /*文件被找到*/ return 0; else /*继续寻找其它路径*/ i = 0; } p++; }/*搜索完所有路径,依然没有找到则返回-1*/ return -1;}int redirect(char *in,int len){ char *argv[30],*filename[2]; pid_t pid; int i,j,k,fd_in,fd_out,is_in = -1,is_out = -1,num = 0; int is_back = 0,status=0;/*这里是重定向的命令解析过程,其中filename用于存放重定向文件, *is_in, is_out分别是输入重定向标记和输出重定向标记*/ for (i = 0,j = 0,k = 0;i <= len;i++){ if (in[i]==" "||in[i]==" "||in[i]==""||in[i] =="<"||in[i]==">"){ if (in[i] == ">" || in[i] == "<"){/*重定向指令最多"<",">"各出现一次,因此num最大为2, *否则认为命令输入错误*/ if (num < 3){ num ++; if (in[i] == "<") is_in = num - 1; else is_out = num - 1; /*处理命令和重定向符号相连的情况,比如ls>a*/ if (j > 0 && num == 1) { buffer[j++] = ""; argv[k] = (char *) malloc(sizeof(char)*j); strcpy(argv[k],buffer); k++; j = 0; } } else{ printf("The format is error! "); return -1; } } if (j == 0) continue; else{ buffer[j++] = ""; /*尚未遇到重定向符号,字符串是命令或参数*/ if (num == 0){ argv[k] = (char *) malloc(sizeof(char)*j); strcpy(argv[k],buffer); k++; } /*是重定向后符号的字符串,是文件名*/ else{ filename[status] = (char *) malloc(sizeof(char)*j); strcpy(filename[status++],buffer); } j = 0; /*initate*/ } } else{ if (in[i] == "&" && in[i+1] == ""){ is_back = 1; continue; } buffer[j++] = in[i]; } } argv[k] = (char *) 0; if (is_fileexist(argv[0]) == -1 ){ printf("This command is not founded! "); for(i=0;i<k;i++) free(argv[i]); return 0; } if ((pid = fork()) ==0){ /*存在输出重定向*/ if (is_out != -1) if((fd_out=open(filename[is_out],O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR))==-1){ printf("Open out %s Error ",filename[is_out]); return -1; } /*存在输入重定向*/ if (is_in != -1) if((fd_in=open(filename[is_in],O_RDONLY,S_IRUSR|S_IWUSR))==-1){ printf("Open in %s Error ",filename[is_out]); return -1; } if (is_out != -1) /*使用dup2函数将标准输出重定向到fd_out上,dup2(int oldfd,int newfd)实现的 *是把oldfd所指的文件描述符复制到newfd。若newfd为一已打开的文件描述词, *则newfd所指的文件会先被关闭,dup2复制的文件描述词与原来的文件描述词 *共享各种文件状态*/ if(dup2(fd_out,STDOUT_FILENO)==-1){ printf("Redirect Standard Out Error "); exit(1); } if (is_in != -1) if(dup2(fd_in,STDIN_FILENO)==-1){ printf("Redirect Standard Out Error "); exit(1); } execv(buffer,argv); } else if (is_back == 0) /*run on the TOP*/ waitpid(pid,&status,0); for (i=0;i<k;i++) free(argv[i]); if (is_in != -1){ free(filename[is_in]); close(fd_in); } if (is_out != -1){ free(filename[is_out]); close(fd_out); } return 0;}int pipel(char *input,int len){ char *argv[2][30]; int i,j,k,count,is_back = 0; int li_comm = 0,fd[2],fpip[2]; char lc_char,lc_end[1]; pid_t child1,child2;/*管道的命令解析过程*/ for (i = 0,j = 0,k = 0;i <= len;i++){ if (input[i]== " " || input[i] == " " || input[i] == "" || input[i] == "|"){ if (input[i] == "|" ) /*管道符号*/ { if (j > 0) { buffer[j++] = ""; /*因为管道连接的是两个指令,所以用二维数组指针来存放命令和参数, *li_comm是表示第几个指令*/ argv[li_comm][k] = (char *) malloc(sizeof(char)*j); strcpy(argv[li_comm][k++],buffer); } argv[li_comm][k++] = (char *) 0; /*遇到管道符,第一个指令完毕,开始准备接受第二个指令*/ li_comm++; count = k; k=0;j=0; } if (j == 0) continue; else { buffer[j++] = ""; argv[li_comm][k] = (char *) malloc(sizeof(char)*j); strcpy(argv[li_comm][k],buffer); k++; } j = 0; /*initate*/ } else{ if (input[i] == "&" && input[i+1] == ""){ is_back = 1; continue; } buffer[j++] = input[i]; } } argv[li_comm][k++] = (char *) 0; if (is_fileexist(argv[0][0]) == -1 ){ printf("This first command is not found! "); for(i=0;i<count;i++) free(argv[0][i]); return 0; }/*指令解析结束*//*建立管道*/ if (pipe(fd) == -1 ){ printf("open pipe error! "); return -1; }/*创建第一个子进程执行管道符前的指令,并将输出写到管道*/ if ((child1 = fork()) ==0){/*关闭读端*/ close(fd[0]); if (fd[1] != STDOUT_FILENO){ /*将标准输出重定向到管道的写入端,这样该子进程的输出就写入了管道*/ if (dup2(fd[1],STDOUT_FILENO) == -1){ printf("Redirect Standard Out Error "); return -1; } /*关闭写入端*/ close(fd[1]); } execv(buffer,argv[0]); } else{ /*父进程*//*先要等待写入管道的进程结束*/ waitpid(child1,&li_comm,0); /*然后我们必须写入一个结束标记,告诉读管道进程数据到这里就完了*/ lc_end[0] = 0x1a; write(fd[1],lc_end,1); close(fd[1]); if (is_fileexist(argv[1][0]) == -1 ){ printf("This command is not founded! "); for(i=0;i<k;i++) free(argv[1][i]); return 0; } /*创建第二个进程执行管道符后的指令,并从管道读输入流 */ if ((child2 = fork()) == 0){ if (fd[0] != STDIN_FILENO){ /*将标准输入重定向到管道读入端*/ if(dup2(fd[0],STDIN_FILENO) == -1){ printf("Redirect Standard In Error! "); return -1; } close(fd[0]); } execv(buffer,argv[1]); } else /*父进程*/ if (is_back == 0) waitpid(child2,NULL,0); } for (i=0;i<count;i++) free(argv[0][i]); for (i=0;i<k;i++) free(argv[1][i]); return 0;}以前写的,好像一些细节不一样,不明白的地方,发邮件给我,shike13@163.com2023-07-17 14:15:191
c语言 编写一个函数,来判断一个数是否是回文数。(回文数就是像12321,正着读和倒着读都一样)
代码:int IsEchoNum(int num){int tmp=0;for(int n=num;n;n/=10)tmp=tmp*10+n%10;return tmp==num;}int main(int argc,char*argv[]){int num=12321;printf("%d%d ",num,IsEchoNum(num));}扩展资料:system()—执行shell命令也就是向dos发送一条指令。相关函数:fork,execve,waitpid,popen头文件:#include<stdlib.h>定义函数:int system(const char*string);system("pause")可以实现冻结屏幕,便于观察程序的执行结果;system("CLS")可以实现清屏操作。而调用color函数可以改变控制台的前景色和背景,具体参数在下面说明。例如,用system("color 0A");其中color后面的0是背景色代号,A是前景色代号。各颜色代码如下:0=黑色1=蓝色2=绿色3=湖蓝色4=红色5=紫色6=黄色7=白色8=灰色9=淡蓝色A=淡绿色B=淡浅绿色C=淡红色D=淡紫色E=淡黄色F=亮白色参考资料:百度百科——system()2023-07-17 14:15:542
system在C语言里是什么意思
system()函数功能强大,很多人用却对它的原理知之甚少先看linux版system函数的源码:#include <sys/types.h>#include <sys/wait.h>#include <errno.h>#include <unistd.h>int system(const char * cmdstring){ pid_t pid; int status; if(cmdstring == NULL){ return (1); } if((pid = fork())<0){ status = -1; } else if(pid = 0){ execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); -exit(127); //子进程正常执行则不会执行此语句 } else{ while(waitpid(pid, &status, 0) < 0){ if(errno != EINTER){ status = -1; break; } } } return status;}分析一下原理估计就能看懂了: 当system接受的命令为NULL时直接返回,否则fork出一个子进程,因为fork在两个进程:父进程和子进程中都返回,这里要检查返回的pid,fork在子进程中返回0,在父进程中返回子进程的pid,父进程使用waitpid等待子进程结束,子进程则是调用execl来启动一个程序代替自己,execl("/bin/sh", "sh", "-c", cmdstring, (char*)0)是调用shell,这个shell的路径是/bin/sh,后面的字符串都是参数,然后子进程就变成了一个shell进程,这个shell的参数是cmdstring,就是system接受的参数。在windows中的shell是command,想必大家很熟悉shell接受命令之后做的事了。再解释下fork的原理:当一个进程A调用fork时,系统内核创建一个新的进程B,并将A的内存映像复制到B的进程空间中,因为A和B是一样的,那么他们怎么知道自己是父进程还是子进程呢,看fork的返回值就知道,上面也说了fork在子进程中返回0,在父进程中返回子进程的pid。windows中的情况也类似,就是execl换了个又臭又长的名字,参数名也换的看了让人发晕的,我在MSDN中找到了原型,给大家看看:HINSTANCE ShellExecute( HWND hwnd, LPCTSTR lpVerb, LPCTSTR lpFile, LPCTSTR lpParameters, LPCTSTR lpDirectory, INT nShowCmd ); 用法见下:ShellExecute(NULL, "open", "c:\a.reg", NULL, NULL, SW_SHOWNORMAL); 你也许会奇怪 ShellExecute中有个用来传递父进程环境变量的参数 lpDirectory,linux中的execl却没有,这是因为execl是编译器的函数(在一定程度上隐藏具体系统实现),在linux中它会接着产生一个linux系统的调用 execve, 原型见下:int execve(const char * file,const char **argv,const char **envp);看到这里就会明白为什么system()会接受父进程的环境变量,但是用system改变环境变量后,system一返回主函数还是没变。原因从system的实现可以看到,它是通过产生新进程实现的,从我的分析中可以看到父进程和子进程间没有进程通信,子进程自然改变不了父进程的环境变量。使用了system函数就能执行dos指令。#include <stdio.h>#include <stdlib.h>xiaoyu(){char *a;int n=0;FILE *f;f=fopen("file.bat","w+");/*新建一个批处理*/if(f==NULL)exit(1); a="echo"; /*DOS命令*/ for(n=65;n<=90;n++)/*大写A-Z*/ fprintf(f,"%s %c ",a,n);/*利用ASCII码输出A-Z,写出批处理*/ fclose(f); system("file.bat");/*运行批处理*/}main(){ char *string; xiaoyu(); string="echo C语言的system函数 ";/*输出中文*/ system(string); system("pause");/*程序暂停*/}C中可以使用DOS命令,以后编程通过调用DOS命令很多操作就简单多了。2023-07-17 14:16:093
QT中能不能调用C语言的API。linux下的
QT如果是C++版就能够调用C语言的函数,只要你用了相应的库包函。你说调用fork, waitpid, exec, thread_create, socket, connect, accept这些函数不知道每个函数的意思是什么.但是,在QT里这些函数应该在QT里已经都有了的,至少我看到你说的exec,socket,connect,accept这些函数我都用了的,但是不知道你说的fork,waitpid,thread_create是什么函数,thread_create如果是建立线程的话,在QT里创建线程更简单。QT里面很少用到C的基本函数,因为QT的功能本身就比较强大,但是QT不是面向过程的集成开发环境,它是面向对象的,如果你只学了C的话,最好再学学C++吧。只有学了C++才能更好的学,不然你学起来非常痛苦,相反如果学了C++就轻松得多,至少比VC++更轻松。2023-07-17 14:16:194
如何快速找到系统调用的内核源码
问题:经常需要在内核中查找系统调用的定义,比如sys_waitpid,如何快速找到呢?解决:1、在老版本内核中,系统调用通常定义为sys_*,所以可以直接通过相关符号查找。2、但新版本中,系统的调用方式不同,采用了SYSCALL_DEFINE的定义方式,由于各系统调用的实现比较分散,查找起来不算方便。具体查找方法如下:1)通过sys_*的方式找到相应函数的声明,如(include/linux/Syscall.h):asmlinkage long sys_waitpid(pid_t pid, int __user *stat_addr, int options);确认该声明中的参数个数,这里为3,这继续查找SYSCALL_DEFINE3(waitpid*)即可,可以通过正则表达式搜索,也可以直接搜索waitpid的引用,查找SYSCALL_DEFINE3(waitpid*)所在的位置,sys_waitpid定义如下(kernel/exit.c):SYSCALL_DEFINE3(waitpid, pid_t, pid, int __user *, stat_addr, int, options){return sys_wait4(pid, stat_addr, options, NULL);}此处,有涉及另一个系统调用sys_wait4的定义,需要继续用上述方法查找,该系统调用有4个参数,所以应该查找SYSCALL_DEFINE4(wait4*),或者查找wait4的引用,可以找到相应结果(kernel/exit.c)。SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr,int, options, struct rusage __user *, ru){...}新版本内核中系统调用的定义方式如下(使用了宏定义,定义更简单,但可读性比较差~),供参考:#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)#define SYSCALL_DEFINEx(x, sname, ...) SYSCALL_METADATA(sname, x, __VA_ARGS__) __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)#define __PROTECT(...) asmlinkage_protect(__VA_ARGS__)#define __SYSCALL_DEFINEx(x, name, ...) asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)); asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) { long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__)); __MAP(x,__SC_TEST,__VA_ARGS__); __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); return ret; } SYSCALL_ALIAS(sys##name, SyS##name); static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))2023-07-17 14:16:271
如何查看进程id?
方法如下:第一步,进入操作系统桌面。第二步,右键任务栏,点选启动任务管理器。第三步,弹出任务管理器窗口。第四步,点击查看->选择列。第五步,弹出选择进程页列的窗口。第六步,点选会话ID的复选框,点击确定。第七步,回到刚才的任务管理器,可以看到会话ID的一列数据。进程ID(英语:processID)、PID)是大多数操作系统的内核用于唯一标识进程的一个数值。(简言之,就是进程的绰号。)这一数值可以作为许多函数调用的参数,以使调整进程优先级、kill(命令)进程之类的进程控制行为成为可能。在类UNIX操作系统中,新进程都衍自系统调用fork函数(英语:Fork (operating system))。fork()调用会将子进程的PID返回给父进程,使其可以之指代子进程,从而在需要时以之为函数参数。例如,若以子进程PID为参数调用waitpid(),可使父进程以休眠状态等待子进程结束;若以之为参数调用kill()(英语:kill (command)),便可结束对应子进程。2023-07-17 14:16:351
C语言问题。
[color=blue]2)Linux程序设计入门--进程介绍[/color] Linux下进程的创建 前言: 这篇文章是用来介绍在Linux下和进程相关的各个概念.我们将会学到: 进程的概念 进程的身份 进程的创建 守护进程的创建 ---------------------------------------------------------------------------- ---- 1。进程的概念 Linux操作系统是面向多用户的.在同一时间可以有许多用户向操作系统发出各种命 令.那么操作系统是怎么实现多用户的环境呢? 在现代的操作系统里面,都有程序和进程 的概念.那么什么是程序,什么是进程呢? 通俗的讲程序是一个包含可以执行代码的文件 ,是一个静态的文件.而进程是一个开始执行但是还没有结束的程序的实例.就是可执行文 件的具体实现. 一个程序可能有许多进程,而每一个进程又可以有许多子进程.依次循环 下去,而产生子孙进程. 当程序被系统调用到内存以后,系统会给程序分配一定的资源(内 存,设备等等)然后进行一系列的复杂操作,使程序变成进程以供系统调用.在系统里面只 有进程没有程序,为了区分各个不同的进程,系统给每一个进程分配了一个ID(就象我们的 身份证)以便识别. 为了充分的利用资源,系统还对进程区分了不同的状态.将进程分为新 建,运行,阻塞,就绪和完成五个状态. 新建表示进程正在被创建,运行是进程正在运行,阻 塞是进程正在等待某一个事件发生,就绪是表示系统正在等待CPU来执行命令,而完成表示 进程已经结束了系统正在回收资源. 关于进程五个状态的详细解说我们可以看《操作系 统》上面有详细的解说。 2。进程的标志 上面我们知道了进程都有一个ID,那么我们怎么得到进程的ID呢?系统调用getpid可 以得到进程的ID,而getppid可以得到父进程(创建调用该函数进程的进程)的ID. #include <unistd>; pid_t getpid(void); pid_t getppid(void); 进程是为程序服务的,而程序是为了用户服务的.系统为了找到进程的用户名,还为进程和 用户建立联系.这个用户称为进程的所有者.相应的每一个用户也有一个用户ID.通过系统 调用getuid可以得到进程的所有者的ID.由于进程要用到一些资源,而Linux对系统资源是 进行保护的,为了获取一定资源进程还有一个有效用户ID.这个ID和系统的资源使用有关 ,涉及到进程的权限. 通过系统调用geteuid我们可以得到进程的有效用户ID. 和用户ID 相对应进程还有一个组ID和有效组ID系统调用getgid和getegid可以分别得到组ID和有效 组ID #include <unistd>; #include <sys/types.h>; uid_t getuid(void); uid_t geteuid(void); gid_t getgid(void); git_t getegid(void); 有时候我们还会对用户的其他信息感兴趣(登录名等等),这个时候我们可以调用getpwui d来得到. struct passwd { char *pw_name; /* 登录名称 */ char *pw_passwd; /* 登录口令 */ uid_t pw_uid; /* 用户ID */ gid_t pw_gid; /* 用户组ID */ char *pw_gecos; /* 用户的真名 */ char *pw_dir; /* 用户的目录 */ char *pw_shell; /* 用户的SHELL */ }; #include <pwd.h>; #include <sys/types.h>; struct passwd *getpwuid(uid_t uid); 下面我们学习一个实例来实践一下上面我们所学习的几个函数: #include <unistd.h>; #include <pwd.h>; #include <sys/types.h>; #include <stdio.h>; int main(int argc,char **argv) { pid_t my_pid,parent_pid; uid_t my_uid,my_euid; gid_t my_gid,my_egid; struct passwd *my_info; my_pid=getpid(); parent_pid=getppid(); my_uid=getuid(); my_euid=geteuid(); my_gid=getgid(); my_egid=getegid(); my_info=getpwuid(my_uid); printf("Process ID:%ld ",my_pid); printf("Parent ID:%ld ",parent_pid); printf("User ID:%ld ",my_uid); printf("Effective User ID:%ld ",my_euid); printf("Group ID:%ld ",my_gid); printf("Effective Group ID:%ld ",my_egid): if(my_info) { printf("My Login Name:%s " ,my_info->;pw_name); printf("My Password :%s " ,my_info->;pw_passwd); printf("My User ID :%ld ",my_info->;pw_uid); printf("My Group ID :%ld ",my_info->;pw_gid); printf("My Real Name:%s " ,my_info->;pw_gecos); printf("My Home Dir :%s ", my_info->;pw_dir); printf("My Work Shell:%s ", my_info->;pw_shell); } } 3。进程的创建 创建一个进程的系统调用很简单.我们只要调用fork函数就可以了. #include <unistd.h>; pid_t fork(); 当一个进程调用了fork以后,系统会创建一个子进程.这个子进程和父进程不同的地方只 有他的进程ID和父进程ID,其他的都是一样.就象符进程克隆(clone)自己一样.当然创建 两个一模一样的进程是没有意义的.为了区分父进程和子进程,我们必须跟踪fork的返回 值. 当fork掉用失败的时候(内存不足或者是用户的最大进程数已到)fork返回-1,否则f ork的返回值有重要的作用.对于父进程fork返回子进程的ID,而对于fork子进程返回0.我 们就是根据这个返回值来区分父子进程的. 父进程为什么要创建子进程呢?前面我们已经 说过了Linux是一个多用户操作系统,在同一时间会有许多的用户在争夺系统的资源.有时 进程为了早一点完成任务就创建子进程来争夺资源. 一旦子进程被创建,父子进程一起从 fork处继续执行,相互竞争系统的资源.有时候我们希望子进程继续执行,而父进程阻塞直 到子进程完成任务.这个时候我们可以调用wait或者waitpid系统调用. #include <sys/types.h>; #include <sys/wait.h>; pid_t wait(int *stat_loc); pid_t waitpid(pid_t pid,int *stat_loc,int options); wait系统调用会使父进程阻塞直到一个子进程结束或者是父进程接受到了一个信号.如果 没有父进程没有子进程或者他的子进程已经结束了wait回立即返回.成功时(因一个子进 程结束)wait将返回子进程的ID,否则返回-1,并设置全局变量errno.stat_loc是子进程的 退出状态.子进程调用exit,_exit 或者是return来设置这个值. 为了得到这个值Linux定 义了几个宏来测试这个返回值. WIFEXITED:判断子进程退出值是非0 WEXITSTATUS:判断子进程的退出值(当子进程退出时非0). WIFSIGNALED:子进程由于有没有获得的信号而退出. WTERMSIG:子进程没有获得的信号号(在WIFSIGNALED为真时才有意义). waitpid等待指定的子进程直到子进程返回.如果pid为正值则等待指定的进程(pid).如果 为0则等待任何一个组ID和调用者的组ID相同的进程.为-1时等同于wait调用.小于-1时等 待任何一个组ID等于pid绝对值的进程. stat_loc和wait的意义一样. options可以决定 父进程的状态.可以取两个值 WNOHANG:父进程立即返回当没有子进程存在时. WUNTACHE D:当子进程结束时waitpid返回,但是子进程的退出状态不可得到. 父进程创建子进程后,子进程一般要执行不同的程序.为了调用系统程序,我们可以使用系 统调用exec族调用.exec族调用有着5个函数. #include <unistd.h>; int execl(const char *path,const char *arg,...); int execlp(const char *file,const char *arg,...); int execle(const char *path,const char *arg,...); int execv(const char *path,char *const argv[]); int execvp(const char *file,char *const argv[]): exec族调用可以执行给定程序.关于exec族调用的详细解说可以参考系统手册(man exec l). 下面我们来学习一个实例.注意编译的时候要加 -lm以便连接数学函数库. #include <unistd.h>; #include <sys/types.h>; #include <sys/wait.h>; #include <stdio.h>; #include <errno.h>; #include <math.h>; void main(void) { pid_t child; int status; printf("This will demostrate how to get child status "); if((child=fork())==-1) { printf("Fork Error :%s ",strerror(errno)); exit(1); } else if(child==0) { int i; printf("I am the child:%ld ",getpid()); for(i=0;i<1000000;i++) sin(i); i=5; printf("I exit with %d ",i); exit(i); } while(((child=wait(&status))==-1)&(errno==EINTR)); if(child==-1) printf("Wait Error:%s ",strerror(errno)); else if(!status) printf("Child %ld terminated normally return status is zero ", child); else if(WIFEXITED(status)) printf("Child %ld terminated normally return status is %d ", child,WEXITSTATUS(status)); else if(WIFSIGNALED(status)) printf("Child %ld terminated due to signal %d znot caught ", child,WTERMSIG(status)); } strerror函数会返回一个指定的错误号的错误信息的字符串. 4。守护进程的创建 如果你在DOS时代编写过程序,那么你也许知道在DOS下为了编写一个常驻内存的程序 我们要编写多少代码了.相反如果在Linux下编写一个"常驻内存"的程序却是很容易的.我 们只要几行代码就可以做到. 实际上由于Linux是多任务操作系统,我们就是不编写代码 也可以把一个程序放到后台去执行的.我们只要在命令后面加上&符号SHELL就会把我们的 程序放到后台去运行的. 这里我们"开发"一个后台检查邮件的程序.这个程序每个一个指 定的时间回去检查我们的邮箱,如果发现我们有邮件了,会不断的报警(通过机箱上的小喇 叭来发出声音). 后面有这个函数的加强版本加强版本 后台进程的创建思想: 首先父进程创建一个子进程.然后子进程杀死父进程(是不是很无 情?). 信号处理所有的工作由子进程来处理. #include <unistd.h>; #include <sys/types.h>; #include <sys/stat.h>; #include <stdio.h>; #include <errno.h>; #include <fcntl.h>; #include <signal.h>; /* Linux 的默任个人的邮箱地址是 /var/spool/mail/用户的登录名 */ #define MAIL "/var/spool/mail/hoyt" /* 睡眠10秒钟 */ #define SLEEP_TIME 10 main(void) { pid_t child; if((child=fork())==-1) { printf("Fork Error:%s ",strerror(errno)); exit(1); } else if(child>;0) while(1); if(kill(getppid(),SIGTERM)==-1) { printf("Kill Parent Error:%s ",strerror(errno)); exit(1); } { int mailfd; while(1) { if((mailfd=open(MAIL,O_RDONLY))!=-1) { fprintf(stderr,"%s","07"); close(mailfd); } sleep(SLEEP_TIME); } } } 你可以在默认的路径下创建你的邮箱文件,然后测试一下这个程序.当然这个程序还有很 多地方要改善的.我们后面会对这个小程序改善的,再看我的改善之前你可以尝试自己改 善一下.比如让用户指定邮相的路径和睡眠时间等等.相信自己可以做到的.动手吧,勇敢 的探险者. 好了进程一节的内容我们就先学到这里了.进程是一个非常重要的概念,许多的程序都会 用子进程.创建一个子进程是每一个程序员的基本要求!2023-07-17 14:17:182
linux下多进程或者多线程编程的问题。新手,望指教!
第一个问题,不管是创建进程或者创建线程都不会阻塞,创建完毕马上返回不会等待子进程或者子线程的运行第二个问题首先进程和线程是不一样的多进程时,父进程如果先结束,那么子进程会被init进程接收成为init进程的子进程,接下来子进程接着运行,直到结束,init进程负责取得这些子进程的结束状态并释放进程资源。而如果是子进程先结束,那么父进程应当用wait或者waitpid去获取子进程的结束状态并释放进程资源,否则子进程会成为僵死进程,它占用的进程资源不会释放多线程时,如果父线程或者说你讲的main结束时使用return或者exit或者处理完毕结束,那么整个进程都结束,其他子线程自然结束。如果main结束时使用的是pthread_exit那么只有父线程结束,子线程还在运行。同样对于子线程结束时如果调用了exit,那么整个进程包括父线程结束,如果调用了pthread_exit或者正常结束,那么只有子线程结束。另外子线程结束时如果没有分离属性,其他线程应当使用pthread_join去获取线程结束状态并释放线程资源,如同进程里的wait和waitpid2023-07-17 14:17:282
什么是进程Id
进程ID(英语:processID)、PID)是大多数操作系统的内核用于唯一标识进程的一个数值。(简言之,就是进程的绰号。)这一数值可以作为许多函数调用的参数,以使调整进程优先级、kill(命令)进程之类的进程控制行为成为可能。在类UNIX操作系统中,新进程都衍自系统调用fork函数(英语:Fork (operating system))。fork()调用会将子进程的PID返回给父进程,使其可以之指代子进程,从而在需要时以之为函数参数。例如,若以子进程PID为参数调用waitpid(),可使父进程以休眠状态等待子进程结束;若以之为参数调用kill()(英语:kill (command)),便可结束对应子进程。在各PID中,较为特别的是0号PID和1号PID。PID为0者为交换进程(英语:swapper),属于内核进程,负责分页任务;PID为1者则常为init进程,主要负责启动与关闭系统。值得一提的是,1号PID本来并非是特意为init进程预留的,而init进程之所以拥有这一PID,则是因为init即是内核创建的第一个进程。不过,现今的许多UNIX/类UNIX系统内核也有以进程形式存在的其他组成部分,而在这种情况下,1号PID则仍为init进程保有,以与之前系统保持一致。PID的分配机制则因系统而异,一般从0开始,然后顺序分配,直到达到一个最大值(亦因系统而异),而后又从300开始重新分配;在Mac OS X和HP-UX下,则是由100开始重分配。在分配PID时,若遇到已分配的PID,则直接跳过,继续递增查找下一个可分配PID。2023-07-17 14:17:372
请问如何在fork()后让子进程先等待父进程退出?
我感觉你似乎可以用getppid获取父进程pid,然后waitpid,我猜的,你不妨试试,不行的话不要怪我,哈哈如果waitpid不能wait父进程的话,或许你应该使用某种同步锁,比如mutex自己实现这种同步.2023-07-17 14:17:442
linux下socket 网络编程(客户端向服务器端发送文件) 求源代码 大哥大姐帮帮忙 。。谢谢
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <netinet/in.h>#include <sys/socket.h>#include <arpa/inet.h>main(){ int serverfd=socket(AF_INET,SOCK_STREAM,0); if(serverfd==-1) printf("服务器socket建立失败:%m "),exit(-1); printf("服务器socket建立成功! "); struct sockaddr_in addr; addr.sin_family=AF_INET; addr.sin_port=htons(11112); inet_aton("192.168.180.92",&addr.sin_addr); int r=bind(serverfd,(struct sockaddr*)&addr,sizeof(addr)); if(r==-1) printf("绑定地址失败:%m "),exit(-1); printf("绑定地址成功! "); r=listen(serverfd,10); if(r==-1) printf("监听服务socket变化失败:%m "),exit(-1); printf("监听服务器socket成功! "); struct sockaddr_in caddr; socklen_t len; while(1) { len=sizeof caddr; int fd=accept(serverfd,(struct sockaddr*)&caddr,&len); printf("有人连接:%s:%d ", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port)); }}这是服务器端的,客户端的只要去掉监听,连接,再把发送接收数据改一下,就能用了2023-07-17 14:17:511
Wait的函数
wait(等待子进程中断或结束)相关函数 waitpid,fork表头文件#include<sys/types.h>#include<sys/wait.h>定义函数 pid_t wait (int * status);函数说明wait()会暂时停止进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数status 返回,而子进程的进程识别码也会一起返回。如果不在意结束状态值,则参数status 可以设成NULL。子进程的结束状态值请参考下面的waitpid()。返回值如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。失败原因存于errno 中。附加说明范例#include<stdlib.h>#include<unistd.h>#include<sys/types.h>#include<sys/wait.h>main()pid_t pid;int status,i;if(fork()= =0){printf(“This is the child process .pid =%d ”,getpid());exit(5);}else{sleep(1);printf(“This is the parent process ,wait for child... ”;pid=wait(&status);i=WEXITSTATUS(status);printf(“child"s pid =%d .exit status=%d ”,pid,i);执行This is the child process.pid=1501This is the parent process .wait for child...child"s pid =1501,exit status =5waitpid(等待子进程中断或结束)相关函数 wait,fork表头文件#include<sys/types.h>#include<sys/wait.h>定义函数 pid_t waitpid(pid_t pid,int * status,int options);函数说明waitpid()会暂时停止进程的执行,而子进程的进程识别码也会一快返回。如果不在意结束状态值,则参数status 可以设成NULL。参数pid 为欲等待的子进程识别码,其他数值意义如下:2023-07-17 14:18:091
如何让进程wait函数返回值
调用wait或waitpid有三种不同的情况发生:1、如果其所有子进程都还在运行,则阻塞2、如果一个子进程终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回3、如果它没有任何子进程,则立即出错返回如果进程由于接收到SIGCHLD信号而调用wait,则可期望wait会立即返回,但是如果在任意时刻调用wait,则进程可能会阻塞。在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞。waitpid并不等待在其调用之后的第一个终止子进程,他有若干选项,可以控制他所等待的进程。2023-07-17 14:18:221
操作系统wait()是什么东西?详细解释下
wait()函数详细解释: wait(等待子进程中断或结束) 相关函数 waitpid,fork 表头文件 #include #include 定义函数 pid_t wait (int * status); 函数说明 wait()会暂时停止目前进程的执行,直到有信号来到或子进程结 束。如果在调用wait()时子进程已经结束,则wait()会立即返 回子进程结束状态值。子进程的结束状态值会由参数status 返回, 而子进程的进程识别码也会一快返回。如果不在意结束状态值,则 参数status 可以设成NULL。子进程的结束状态值请参考waitpid()。 返回值 如果执行成功则返回子进程识别码(PID),如果有错误发生则返回 -1。失败原因存于errno 中。 附加说明 范例 #include #include #include #include main() { pid_t pid; int status,i; if(fork()= =0){ printf(“This is the child process .pid =%d ”,getpid()); exit(5); }else{ sleep(1); printf(“This is the parent process ,wait for child... ”; pid=wait(&status); i=WEXITSTATUS(status); printf(“child"s pid =%d .exit status=^d ”,pid,i); } } 执行 This is the child process.pid=1501 This is the parent process .wait for child... child"s pid =1501,exit status =5 waitpid(等待子进程中断或结束) 相关函数 wait,fork 表头文件 #include #include 定义函数 pid_t waitpid(pid_t pid,int * status,int options); 函数说明 waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程 结束。如果在调用wait()时子进程已经结束,则wait()会立即 返回子进程结束状态值。子进程的结束状态值会由参数status 返回, 而子进程的进程识别码也会一快返回。如果不在意结束状态值,则 参数status 可以设成NULL。参数pid 为欲等待的子进程识别码, 其他数值意义如下: pid0 等待任何子进程识别码为pid 的子进程。 参数option 可以为0 或下面的OR 组合: WNOHANG 如果没有任何已经结束的子进程则马上返回,不予以 等待。 WUNTRACED 如果子进程进入暂停执行情况则马上返回,但结束 状态不予以理会。 子进程的结束状态返回后存于status,底下有几个宏可判别结束情 况: WIFEXITED(status)如果子进程正常结束则为非0 值。 WEXITSTATUS(status)取得子进程exit()返回的结束代码,一 般会先用WIFEXITED 来判断是否正常结束才能使用此宏。 WIFSIGNALED(status)如果子进程是因为信号而结束则此宏值为 真 WTERMSIG(status) 取得子进程因信号而中止的信号代码,一般 会先用WIFSIGNALED 来判断后才使用此宏。 WIFSTOPPED(status) 如果子进程处于暂停执行情况则此宏值为 真。一般只有使用WUNTRACED 时才会有此情况。 WSTOPSIG(status) 取得引发子进程暂停的信号代码,一般会先 用WIFSTOPPED 来判断后才使用此宏。 返回值 如果执行成功则返回子进程识别码(PID),如果有错误发生则返回 -1。失败原因存于errno 中。 范例 参考wait()。本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/60641/showart_488226.html2023-07-17 14:18:292
c程序 中wait:什么意思
这是个标号,比如:Wait: ........if ( xxx ) goto Wait; //转向Wait标号后面的语句执行2023-07-17 14:18:392
waitpid以及kill函数的返回值
WNOHANG 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若结束,则返回该子进程的ID。raise(SIGSTOP);只不过是让子进程暂停,并没有结束进程。所以返回值为0还有ret=kill(result,SIGKILL)==0这句实际是这么执行的ret=(kill(result,SIGKILL)==0)你应该改写成(ret=kill(result,SIGKILL))==02023-07-17 14:18:461
system函数阻塞怎么办
这是进程间同步的问题。解决方法是:fork一个子进程执行system调用,父进程调用 wait 或 waitpid 等待子进程的终止信息。父进程调用 wait 或 waitpid 时可能会:? 阻塞(如果它的所有子进程都还在运行)。? 带子进程的终止信息立即返回(如果一个子进程已终止,正等待父进程读取其终止信息)。? 出错立即返回(如果它没有任何子进程)。wait 和 waitpid 这两个函数的区别是:? 如果父进程的所有子进程都还在运行,调用wait将使父进程阻塞,而调用waitpid时如果在options参数中指定WNOHANG可以使父进程不阻塞而立即返回0。? wait等待第一个终止的子进程,而waitpid可以通过pid参数指定等待哪一个子进程。2023-07-17 14:18:531
linux下system函数调用shell命令后,怎样让主进程等子进程返回后,接着执行
这是进程间同步的问题。解决方法是:fork一个子进程执行system调用,父进程调用 wait 或 waitpid 等待子进程的终止信息。父进程调用 wait 或 waitpid 时可能会:u2022 阻塞(如果它的所有子进程都还在运行)。u2022 带子进程的终止信息立即返回(如果一个子进程已终止,正等待父进程读取其终止信息)。u2022 出错立即返回(如果它没有任何子进程)。wait 和 waitpid 这两个函数的区别是:u2022 如果父进程的所有子进程都还在运行,调用wait将使父进程阻塞,而调用waitpid时如果在options参数中指定WNOHANG可以使父进程不阻塞而立即返回0。u2022 wait等待第一个终止的子进程,而waitpid可以通过pid参数指定等待哪一个子进程。2023-07-17 14:19:011
父进程有多个子进程 wait()是等待哪个子进程啊?
它是等待任意一个,如果有多个子进程,某一个结束,他就会返回结束的子进程的pid。如果要等待特定的子进程,可以使用waitpid这个函数2023-07-17 14:19:091
C语言的sleep,wait,delay函数有什么区别
sleep 参数指定暂停时间, 单位是 s delay 参数指定暂停时间, 单位是 ms 所以 sleep(n) == delay(1000*n) 原型:extern void sleep(unsigned int sec); 用法:#include <system.h 功能:短暂延时 说明:延时sec秒举例:// sleep.c #include <system.h main(){int c;clrscr();printf(" Hello, world!");sleep(1);clrscr();printf(" Hi, guys");getchar();return 0;}原型:extern void delay(unsigned int msec); 用法:#include <system.h 功能:短暂延时 说明:延时msec*4毫秒举例:// delay.c #include <system.h main(){int c;clrscr();printf(" Hello, world!"); delay(250); // 250*4=1000msec=1secclrscr();printf(" Hi, guys");getchar();return 0;}wait(等待子进程中断或结束)相关函数waitpid,fork表头文件#include<sys/types.h #include<sys/wait.h 定义函数pid_t wait (int * status);函数说明 wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态 值。子进程的结束状态值会由参数status 返回,而子进程的进程识别码也会一快返回。如果不在意结束状态值,则参数status可以设成NULL。子进程的结束状态值请参考waitpid()。 返回值如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。失败原因存于errno中。2023-07-17 14:19:182
C语言的sleep,wait,delay函数有什么区别?
wait 是等待子进程的返回sleep 参数指定暂停时间, 单位是 sdelay 参数指定暂停时间, 单位是 ms所以 sleep(n) == delay(1000*n)原型:extern void sleep(unsigned int sec);用法:#include <system.h功能:短暂延时说明:延时sec秒举例:// sleep.c#include <system.hmain(){int c;clrscr();printf(" Hello, world!");sleep(1);clrscr();printf(" Hi, guys");getchar();return 0;}原型:extern void delay(unsigned int msec);用法:#include <system.h功能:短暂延时说明:延时msec*4毫秒举例:// delay.c#include <system.hmain(){int c;clrscr();printf(" Hello, world!");delay(250); // 250*4=1000msec=1secclrscr();printf(" Hi, guys");getchar();return 0;}wait(等待子进程中断或结束)相关函数waitpid,fork表头文件#include<sys/types.h#include<sys/wait.h定义函数pid_t wait (int * status);函数说明wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数status 返回,而子进程的进程识别码也会一快返回。如果不在意结束状态值,则参数status可以设成NULL。子进程的结束状态值请参考waitpid()。返回值如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。失败原因存于errno中。2023-07-17 14:19:271
C语言的sleep,wait,delay函数有什么区别
wait 是等待子进程的返回 sleep 参数指定暂停时间, 单位是 s delay 参数指定暂停时间, 单位是 ms 所以 sleep(n) == delay(1000*n) 原型:extern void sleep(unsigned int sec); 用法:#include <system.h 功能:短暂延时 说明:延时sec秒举例:// sleep.c #include <system.h main(){int c;clrscr();printf(" Hello, world!");sleep(1);clrscr();printf(" Hi, guys");getchar();return 0;}原型:extern void delay(unsigned int msec); 用法:#include <system.h 功能:短暂延时 说明:延时msec*4毫秒举例:// delay.c #include <system.h main(){int c;clrscr();printf(" Hello, world!"); delay(250); // 250*4=1000msec=1secclrscr();printf(" Hi, guys");getchar();return 0;}wait(等待子进程中断或结束)相关函数waitpid,fork表头文件#include<sys/types.h #include<sys/wait.h 定义函数pid_t wait (int * status);函数说明 wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态 值。子进程的结束状态值会由参数status 返回,而子进程的进程识别码也会一快返回。如果不在意结束状态值,则参数status可以设成NULL。子进程的结束状态值请参考waitpid()。 返回值如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。失败原因存于errno中。2023-07-17 14:19:471
如何主进程退出时,Popen出来的进程不被杀掉
答:父进程等待任何进程状态改变,wait立即返.并携带状态改变进程信息.需要等待所进程结束,wait外面套循环. 进程结束父进程才调用wait/waitpid则接收信息.进程变僵尸进程.2023-07-17 14:19:541
perl主进程如何等待多个子进程结束
将“use POSIX ":sys_wait_h";”去掉,还有在主进程中打印子进程中的变量是不对的,主进程不知道子进程的状况,除非你用pipe将变量值传给主进程,###################################################!/usr/bin/perl#use POSIX ":sys_wait_h";my $a=10;for($i=1;$i<=3;$i++){my $pid=fork(); if (!defined($pid)) { print "Error in fork: $!"; exit 1; } if ($pid == 0 ) { if($i==1){ sleep(9); $b1=$a+1; print "$b1 "; exit 0;} elsif($i==2){ sleep(5); $b2=$a+10; print "$b2 "; exit 0;} else{ sleep(3); $b3=$a+100; print "$b3 "; exit 0; }}}print "~~~~~~~~~~split~~~~~~~~~~~ ";while (($collect = waitpid(-1, WNOHANG)) > 0) { 1;}##################### 输出 ##########bsd2# perl test.pl~~~~~~~~~~split~~~~~~~~~~~110 20 11 bsd2#2023-07-17 14:20:012
什么是connect()系统调用
由操作系统实现的所有系统调用所构成的集合即程序接口或应用编程接口(Application Programming Interface,API)。是应用程序同系统之间的接口。 Linux系统调用,包含了大部分常用系统调用和由系统调用派生出的的函数。 一、进程控制: fork 创建一个新进程 clone 按指定条件创建子进程 execve 运行可执行文件 exit 中止进程 _exit 立即中止当前进程 getdtablesize 进程所能打开的最大文件数 getpgid 获取指定进程组标识号 setpgid 设置指定进程组标志号 getpgrp 获取当前进程组标识号 setpgrp 设置当前进程组标志号 getpid 获取进程标识号 getppid 获取父进程标识号 getpriority 获取调度优先级 setpriority 设置调度优先级 modify_ldt 读写进程的本地描述表 nanosleep 使进程睡眠指定的时间 nice 改变分时进程的优先级 pause 挂起进程,等待信号 personality 设置进程运行域 prctl 对进程进行特定操作 ptrace 进程跟踪 sched_get_priority_max 取得静态优先级的上限 sched_get_priority_min 取得静态优先级的下限 sched_getparam 取得进程的调度参数 sched_getscheduler 取得指定进程的调度策略 sched_rr_get_interval 取得按RR算法调度的实时进程的时间片长度 sched_setparam 设置进程的调度参数 sched_setscheduler 设置指定进程的调度策略和参数 sched_yield 进程主动让出处理器,并将自己等候调度队列队尾 vfork 创建一个子进程,以供执行新程序,常与execve等同时使用 wait 等待子进程终止 wait3 参见wait waitpid 等待指定子进程终止 wait4 参见waitpid capget 获取进程权限 capset 设置进程权限 getsid 获取会晤标识号 setsid 设置会晤标识号 二、文件系统控制 1、文件读写操作 fcntl 文件控制 open 打开文件 creat 创建新文件 close 关闭文件描述字 read 读文件 write 写文件 readv 从文件读入数据到缓冲数组中 writev 将缓冲数组里的数据写入文件 pread 对文件随机读 pwrite 对文件随机写 lseek 移动文件指针 _llseek 在64位地址空间里移动文件指针 dup 复制已打开的文件描述字 dup2 按指定条件复制文件描述字 flock 文件加/解锁 poll I/O多路转换 truncate 截断文件 ftruncate 参见truncate umask 设置文件权限掩码 fsync 把文件在内存中的部分写回磁盘 2、文件系统操作 access 确定文件的可存取性 chdir 改变当前工作目录 fchdir 参见chdir chmod 改变文件方式 fchmod 参见chmod chown 改变文件的属主或用户组 fchown 参见chown lchown 参见chown chroot 改变根目录 stat 取文件状态信息 lstat 参见stat fstat 参见stat statfs 取文件系统信息 fstatfs 参见statfs readdir 读取目录项 getdents 读取目录项 mkdir 创建目录 mknod 创建索引节点 rmdir 删除目录 rename 文件改名 link 创建链接 symlink 创建符号链接 unlink 删除链接 readlink 读符号链接的值 mount 安装文件系统 umount 卸下文件系统 ustat 取文件系统信息 utime 改变文件的访问修改时间 utimes 参见utime quotactl 控制磁盘配额 三、系统控制 ioctl I/O总控制函数 _sysctl 读/写系统参数 acct 启用或禁止进程记账 getrlimit 获取系统资源上限 setrlimit 设置系统资源上限 getrusage 获取系统资源使用情况 uselib 选择要使用的二进制函数库 ioperm 设置端口I/O权限 iopl 改变进程I/O权限级别 outb 低级端口操作 reboot 重新启动 swapon 打开交换文件和设备 swapoff 关闭交换文件和设备 bdflush 控制bdflush守护进程 sysfs 取核心支持的文件系统类型 sysinfo 取得系统信息 adjtimex 调整系统时钟 alarm 设置进程的闹钟 getitimer 获取计时器值 setitimer 设置计时器值 gettimeofday 取时间和时区 settimeofday 设置时间和时区 stime 设置系统日期和时间 time 取得系统时间 times 取进程运行时间 uname 获取当前UNIX系统的名称、版本和主机等信息 vhangup 挂起当前终端 nfsservctl 对NFS守护进程进行控制 vm86 进入模拟8086模式 create_module 创建可装载的模块项 delete_module 删除可装载的模块项 init_module 初始化模块 query_module 查询模块信息 *get_kernel_syms 取得核心符号,已被query_module代替 四、内存管理 brk 改变数据段空间的分配 sbrk 参见brk mlock 内存页面加锁 munlock 内存页面解锁 mlockall 调用进程所有内存页面加锁 munlockall 调用进程所有内存页面解锁 mmap 映射虚拟内存页 munmap 去除内存页映射 mremap 重新映射虚拟内存地址 msync 将映射内存中的数据写回磁盘 mprotect 设置内存映像保护 getpagesize 获取页面大小 sync 将内存缓冲区数据写回硬盘 cacheflush 将指定缓冲区中的内容写回磁盘 五、网络管理 getdomainname 取域名 setdomainname 设置域名 gethostid 获取主机标识号 sethostid 设置主机标识号 gethostname 获取本主机名称 sethostname 设置主机名称 六、socket控制 socketcall socket系统调用 socket 建立socket bind 绑定socket到端口 connect 连接远程主机 accept 响应socket连接请求 send 通过socket发送信息 sendto 发送UDP信息 sendmsg 参见send recv 通过socket接收信息 recvfrom 接收UDP信息 recvmsg 参见recv listen 监听socket端口 select 对多路同步I/O进行轮询 shutdown 关闭socket上的连接 getsockname 取得本地socket名字 getpeername 获取通信对方的socket名字 getsockopt 取端口设置 setsockopt 设置端口参数 sendfile 在文件或端口间传输数据 socketpair 创建一对已联接的无名socket 七、用户管理 getuid 获取用户标识号 setuid 设置用户标志号 getgid 获取组标识号 setgid 设置组标志号 getegid 获取有效组标识号 setegid 设置有效组标识号 geteuid 获取有效用户标识号 seteuid 设置有效用户标识号 setregid 分别设置真实和有效的的组标识号 setreuid 分别设置真实和有效的用户标识号 getresgid 分别获取真实的,有效的和保存过的组标识号 setresgid 分别设置真实的,有效的和保存过的组标识号 getresuid 分别获取真实的,有效的和保存过的用户标识号 setresuid 分别设置真实的,有效的和保存过的用户标识号 setfsgid 设置文件系统检查时使用的组标识号 setfsuid 设置文件系统检查时使用的用户标识号 getgroups 获取后补组标志清单 setgroups 设置后补组标志清单 八、进程间通信 ipc 进程间通信总控制调用 1、信号 sigaction 设置对指定信号的处理方法 sigprocmask 根据参数对信号集中的信号执行阻塞/解除阻塞等操作 sigpending 为指定的被阻塞信号设置队列 sigsuspend 挂起进程等待特定信号 signal 参见signal kill 向进程或进程组发信号 *sigblock 向被阻塞信号掩码中添加信号,已被sigprocmask代替 *siggetmask 取得现有阻塞信号掩码,已被sigprocmask代替 *sigsetmask 用给定信号掩码替换现有阻塞信号掩码,已被sigprocmask代替 *sigmask 将给定的信号转化为掩码,已被sigprocmask代替 *sigpause 作用同sigsuspend,已被sigsuspend代替 sigvec 为兼容BSD而设的信号处理函数,作用类似sigaction ssetmask ANSI C的信号处理函数,作用类似sigaction 2、消息 msgctl 消息控制操作 msgget 获取消息队列 msgsnd 发消息 msgrcv 取消息 3、管道 pipe 创建管道 4、信号量 semctl 信号量控制 semget 获取一组信号量 semop 信号量操作 5、共享内存 shmctl 控制共享内存 shmget 获取共享内存 shmat 连接共享内存 shmdt 拆卸共享内存2023-07-17 14:20:081