linux下进程编程实验报告Word文件下载.docx
《linux下进程编程实验报告Word文件下载.docx》由会员分享,可在线阅读,更多相关《linux下进程编程实验报告Word文件下载.docx(14页珍藏版)》请在冰豆网上搜索。
Cannotcreatethenewprocess\n"
);
return1;
}
elseif(pid==0)
{
Inthechildprocess!
\n"
else
Intheparentprocess!
运行结果:
[root@BCtest]#./jc_fork
调用fork函数后,其后代码会被父子进程分别执行。
fork();
Willbeexecutedtwice\n"
[root@BCtest]#./jc_fork2
Willbeexecutedtwice
三、vfork函数
intg_var=0;
intvar=1;
processid:
%d\n"
(long)getpid());
beforeexecutetheforksystemcall,g_var=%dvar=%d\n"
g_var,var);
printf("
Cannotcreateanewprocess"
return1;
g_var++;
var++;
processid1:
%d,g_var=%dvar=%d\n"
(long)getpid(),g_var,var);
_exit(0);
processid2:
[root@BCtest]#./fork_jc
2597
beforeexecutetheforksystemcall,g_var=0var=1
2598,g_var=1var=2
2597,g_var=0var=1
由上可知,程序在子进程创建那一刻开始,父进程与子进程分别独立在不同的内存地址空间运行,且子进程复制了父进程的数据,从此数据分开处理。
修改上面程序,将fork函数的语句进行替换,使用vfork函数,将代码保存并运行
if((pid=vfork())<
[root@BCtest]#./fork_jc2
2661
2662,g_var=1var=2
2661,g_var=1var=2
由上可知,程序在子进程创建后,子进程直接在父进程的空间中运行,父进程挂起,直到子进程退出,父进程才再度调用,父进程的数据结构或栈会被子进程改变,g_var与var变为子进程最终的g_var与var。
四、exec函数族
execvp函数支持参数列表,使用参数列表将使程序获得更大的灵活性,程序通过读取agrv中的参数,实现对输入的shell命令的执行。
intmain(intargc,char*argv[])
if(argc<
2)
Usage:
%spath\n"
argv[0]);
execlp("
/bin/ls"
"
ls"
argv[1],(char*)NULL);
程序的功能是调用shell命令中的“ls”,例如在linux终端:
(1)、只输入一位main函数参数:
“exce”
[root@BCtest]#./exec
./execpath
其中path为文件或者目录的路径,而“./exec”则比拟为“ls”
(2)、输入一个文件或目录的路径
[root@BCtest]#./exec/home/bc
01exelhello2.cmyprogstarfun.h.bakyunyun.s
2exel.chello.cmyprog5star.oyun-arm
3exel.exehello.hstar.ctestyun.c
cross-2.95.3.tar.bz2hello2kernelandrootfsstarfun.hwoyun.c.bak
(3)、此程序与“ls”区别是:
要显示当前目录的内容,“ls”只输入“ls”然后回车即可;
而此程序需要输入“./exec./”,即要加上“./”当前目录路径。
五、exit函数
使用atexit注册了一个在进程退出时的处理函数,该处理函数只是显示一段文字信息。
Main函数退出时将调用exit函数,这样进程就会在退出时自动调用atexit注册的函数。
stdlib.h>
voiddo_at_exit(void)
Youcanseetheoutputwhentheprogromterminates\n"
intmain()
intflag;
flag=atexit(do_at_exit);
if(flag!
=0)
Cannotsetexitfunction\n"
returnEXIT_FAILURE;
exit(EXIT_SUCCESS);
OK"
/*检验exit()直接调用atexit注册函数退出*/
[root@BCtest]#./exit
Youcanseetheoutputwhentheprogromterminates
由上面程序可知,atexit注册函数成功返回值为0,所以flag的值为0,exit()直接调用atexit注册函数退出
_exit函数
下面的程序和上面的除了推出函数不同,其他都一样。
不同的是使用_exit函数退出时,不会执行atexit中注册的处理函数。
returnEXIT_FAILURE;
_exit(EXIT_SUCCESS);
[root@BCtest]#./_exit
[root@BCtest]#
执行_exit函数与eint函数,内核都会将打开的文件关闭,将使用的内存地址空间释放,但前者不同是不处理打开的流缓冲区。
(六)、kill函数发送信号
直接用kill函数给进程发送结束信号或是让进程自动退出。
intmain(intargc,char*argv[])
inth;
/*定义一个变量,便于观察if语句的判断*/
intexit_code;
pid=getpid();
pid);
srand((unsigned)pid);
exit_code=(int)(rand()%256);
/*exit_code的十六进制值不超过ff*/
sleep
(1);
h=atoi(*(argv+1))%2;
/*atio()把字符转换为整型,h的值为0或1*/
%d\n"
h);
if(h)/*h=1时,执行语句*/
thechildprocessid:
%drecivesignalSIGKILL\n"
kill(pid,9);
%dnormallyexit_codeis%0x\n"
pid,exit_code);
exit(exit_code);
[root@BCtest]#./kill4
2536
thechildprocessid:
2536normallyexit_codeis25
[root@BCtest]#./kill5
2537
1
2537recivesignalSIGKILL
Killed
[root@BCtest]#./killa
2548
2548normallyexit_codeisc1
由上可知,程序输入的第二参数argv[1],为偶数和字母时,程序调用exit正常退出,为奇数时,程序调用kill自杀退出。
下面程序通过fork函数创建子程序,并调用execl函数执行上面的程序。
为方便了解程序运行的情况,在父进程中显示了创建的子进程的进程号。
在while循环中调用wait函数,跳出条件是wait函数放回值小于0,或wait_pid为-1。
这种情况下,所有的子进程都已经完全退出。
sys/wait.h>
pid_tpid,wait_pid;
intstatus;
inti;
4)
%spara1para2para3\n"
for(i=1;
i<
4;
i++)
if((pid=fork())==0)
execl("
./kill"
kill"
argv[i],NULL);
else
printf("
createthechildprocessid:
while((wait_pid=wait(&
status))&
&
wait_pid!
=-1)
%dexit,exit_codeis%0x\n"
wait_pid,status);
(1)
[root@BCtest]#./p7dfdfdfd
./p7para1para2para3
(2)
[root@BCtest]#./p712a
2935
2936
2937
2935recivesignalSIGKILL
2935exit,exit_codeis9
2936normallyexit_codeisfd
2936exit,exit_codeisfd00
2937normallyexit_codeisbe
2937exit,exit_codeisbe00
七、waitpid函数
使用waitpid等待SIGSTOP,SIGCONT和SIGKILL这三种信号。
pid=fork();
if(pid==-1)
perror("
Cannotcreatnewprocess"
exit
(1);
if(pid==0)
{
childprocessid:
alarm
(1);
//给一个时钟信号,终止子进程
pause();
puts("
pause"
//检查_exit()有没有执行
_exit(0);
}
do
{
wait_pid=waitpid(pid,&
status,0);
//此时pid>
0,等待子进程结束
if(wait_pid==-1)
{
perror("
cannotusingwaitpidfunction\n"
exit
(1);
}
if(WIFEXITED(status))//子进程正常终止,则返回真
printf("
childprocessexites,status=%d\n"
WEXITSTATUS(status));
if(WIFSIGNALED(status))//子进程由信号终止,则返回真
childprocessiskilledbysignal%d\n"
WTERMSIG(status));
if(WIFSTOPPED(status))//信号导致子进程停止,则返回真
childprocessisstoppedbysignal%d\n"
WSTOPSIG(status));
//if(WIFCONTINUED(status))//信号导致子进程继续执行,则返回真
//printf("
childprocessresumerunning...\n"
}
while(!
WIFEXITED(status)&
!
WIFSIGNALED(status));
//信号或正常终止,//则跳出循环
exit(0);
[root@BCtest]#./waitpid
2496
childprocessiskilledbysignal14
(1)、如果去掉第十九行与二十行代码
…
//alarm
(1);
//pause();
2674
pause
childprocessexites,status=0
此程序可使父进程周期性地检查某个特定的子进程是否已终止
八、僵尸进程
if(pid<
cannotcreatednewpeocess\n"
if(pid>
sleep(60);
{perror("
wakeup!
//检查子进程的运行状况
exit(0);
[root@BCtest]#./8_jc
:
Success
注释:
“wakeup!
”是子进程输出的,子进程输出并退出后,父进程还没退出,此时子进程就成为僵尸进程了。
子进程终止时,它与父进程之间的关联会保持到父进程正常终止或父进程调用wait才结束。
子进程成为僵尸进程情况:
A、子进程先于父进程终止,子进程终止后,进程表中代表子进程的表项不会立刻释放,仍存在于系统中,保存以备父进程wait调用使用,于是子进程就成为死进程或僵尸进程。
B、如果父进程先终止,子进程将自动把PID为1的进程,即init,作为父进程,此时子进程是个不再运行的僵尸进程,由init接管,保存在进程表中,直到init进程发现并释放。