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