实验目的:
通过实验掌握下列知识:
1、熟悉wait()系统调用,getpid()系统调用,getppid()系统调用。
2、掌握在Linux下,利用Exec函数族完成其他程序的调用。
3、熟悉在Linux环境下,利用lockf()系统调用完成临界区的互斥。
内容及步骤:
一、
进程创建等待
(1)进程等待
对fork1程序进行修改,让父进程等待并检查子进程的退出状态。Wait.c
子进程的结束状态返回后存于status,下面有几个宏可判别结束情况:
WIFEXITED(status)如果子进程正常结束则为非0
值。
WEXITSTATUS(status)取得子进程exit()返回的结束代码,一般会先用WIFEXITED 来判断是否正常结束才能使用此宏。
WIFSIGNALED(status)如果子进程是因为信号而结束则此宏值为真。
WTERMSIG(status)
取得子进程因信号而中止的信号代码,一般会先用WIFSIGNALED
来判断后才使用此宏。
WIFSTOPPED(status)
如果子进程处于暂停执行情况则此宏值为真。一般只有使用WUNTRACED
时才会有此情况。
WSTOPSIG(status)
取得引发子进程暂停的信号代码,一般会先用WIFSTOPPED
来判断后才使用此宏。
#include
#include
#include
#include
int main ()
{
pid_t pid;
char
*message;
int n;
int
exit_code;
printf(“fork program
starting\n”);
pid=fork();
switch(pid)
{
case -1:
perror(“fork failed!\n”);
exit(1);
case 0:
message=”This is the child”;
n=5;
exit_code=37;
break;
default:
message=”This is the
parent”;
n=3;
exit_code=0;
break;
}
for(;n>0;n--)
{
puts(message);
sleep(1);
}
if(pid!=0)
{
int stat_val;
pid_t child_pid;
child_pid =
wait(&stat_val);
printf(“Child has finished: PID = %d\n”,
child_pid);
if(WIFEXITED(stat_val))
printf(“Child exited with code %d\n”,
WEXITSTATUS(stat_val));
else
printf(“Child terminated
abnormally\n”);
}
exit(exit_code);
}
二、
获取进程ID号
getpid()和getppid(),取得目前进程的识别码(进程ID),许多程序利用取到的此值来建立临时文件,以避免临时文件相同带来的问题。系统调用格式:int
getpid(),getppid()取得目前进程的父进程识别码。
(2)利用getpid()函数和gteppid()函数获取当前子进程和父进程的Pid号。
#include
#include
Int p1,p2;
int main ()
{
P1=fork();
If(p1==0)
Printf(“child 1
%d\n”,getpid());
Else{
P2=fork();
If(p2==0)
Printf(“child 2
%d\n”,getpid());
Else
Printf(“parent
%d\n”,getppid());
}
}
三、
利用Exec函数族调用程序
(3)exec系统调用
#include
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 execve(const char *path,
char *const argv[], char *const envp[]);
在以上六个exec函数中,第一个参数如果为pathname,说明被执行程序是由路径名指定,如果为filename,则说明是由文件名指定;第二个参数如果为数组,说明被执行程序的参数是由一个数组来索引(数组必须含有一个空指针来表示结束),否则需要将参数一一列出;execle()及execve()的envp指针数组表示这两个函数显示指定一个环境表(这个数组必须以一个空指针结束),而另外四个函数则用外部变量environ的当前值来创建一个环境表传递给新程序。
int execl(const char*
fullpath, const char* arg, ....)
使用范例:execl(“/bin/ls”,
”ls”,
”-al”,
NULL)
int execlp(const char* file,
const char* arg, ....)
使用范例:execlp(“ls”,
”ls”,
”-al”,
NULL)
int execle(const char*
fullpath, const char* arg, ...., char* const
envp[])
使用范例:execle(“/bin/ls”,
”ls”,
”-al”, NULL,
environ)
int execv(const char *
fullpath, char* const argv[])
使用范例:execle(“/bin/mkdir”, argv) // int main(int argc,
char* argv[])
或
char* const p[] = {"a.out",
"testDir", NULL};
execv("/bin/mkdir",
p);
int execvp(const char* file,
const char* arg, ....)
使用范例:execlp(“ls”, argv) // int main(int argc,
char* argv[])
或
char* const p[] = {"a.out",
"testDir", NULL};
execvp("mkdir",
p);
int execve(const char*
fullpath, const char* arg, ...., char* const
envp[])
使用范例:execve(“/bin/ls”, argv,
environ)
或
char* const p[] = {"a.out",
"testDir", NULL};
execve("/bin/mkdir",
p);
利用execlp函数显示当前目录下的文件。
#include
#include
#include
#include
int main()
{
pid_t pid1;
pid1=fork();
if(pid1<0)
{fprintf(stderr,"Fork failed!\n");exit(-1);}
else if(pid1==0) {
execl("/bin/ls","ls","-al","/root/4/",NULL);}
else
{wait(NULL);
printf("child
complete!\n");
exit(0);}
return 0;
}
四、
进程互斥lockf( )系统调用
(4)如果在程序中使用系统调用lockf()来给每一个进程加锁,可以实现进程之间的互斥,观察并分析出现的现象。
Lockf(1,1,0)是给屏幕上锁,lockf(1,0,0)是给屏幕解锁。
#include
#include
#include
#include
int p1,p2;
int main()
{
p1=fork();
if(p1==0)
{
for(i=0;i<15;i++)
{
printf("child1
%d\n",i);
sleep(2);
}
}
else
{
p2=fork();
if(p2==0)
{
lockf(1,1,0);
for(i=0;i<15;i++)
{
printf("child2
%d\n",i);
sleep(1);
}
lockf(1,0,0);
}
else
{
lockf(1,1,0);
for(i=0;i<15;i++)
printf("parent
%d\n",i);
lockf(1,0,0);
}
}
在程序中,会出现交替进程运行的情况。
(5)通过文件locked.txt资源,实现进程互斥。
#include
#include
#include
#include
int main()
{
int p1,p2,i;
FILE* fp;
fp =
fopen("locked.txt","w+");
if(fp==NULL)
{
printf("Failed to create
file");
exit(-1);
}
while
((p1=fork())==-1);
if(p1==0)
{
lockf(fp,1,0);
for(i=0;i<10;i++)
fprintf(fp,"child1 is
%d\n",i);
lockf(fp,0,0);
}
else
{
while((p2=fork())==-1);
if(p2==0)
{
lockf(fp,1,0);
for(i=0;i<10;i++)
fprintf(fp,"child2 is
%d\n",i);
lockf(fp,0,0);
}
else
{
wait(NULL);
lockf(fp,1,0);
for(i=0;i<10;i++)
fprintf(fp, "parent is
%d\n",i);
lockf(fp,0,0);
}
}
fclose(fp);
}
./lockfile,运行,结果通过cat
locked.txt运行。