Linux进程创建和控制(fork和lockf)
Linux进程创建和控制
Linux进程创建和控制
一、进程的层次结构
在Linux操作系统中,允许一个进程创建另一个进程,通常把创建进程的进程称为父进程,而把被创建的进程称为子进程。子进程可继续创建更多的孙进程,由此便形成了一个进程的层次结构。子进程可以继承父进程所拥有的资源。
注:windows中不存在任何进程层次结构的概念,所有的进程都具有相同的地位。因此下面的函数和头文件仅存在于Liunx系统中。
二、常用函数
(1)fork函数
#include<unistd.h>
#include<sys/types.h> //头文件
pid_t fork(void) //函数原型
(pid_t 是一个宏定义,其实质是int 被定义在#include<sys/types.h>中)
fork
调用用于创建一个新进程 (子进程 ),它与系统调用fork的进程 (父进程 ) 同时运行。创建新的子进程后,两个进程将执行函数fork
的下一条指令。子进程使用相同的pc (程序计数器 ),相同的CPU寄存器,即子进程把父进程当前的情况拷贝一份,子进程和父进程的资源是相同的。
fork
不需要参数。
fork
会返回两个返回值,一个返回到子进程,一个返回到父进程。
对于返回到子进程的值:① (负值
−
1
-1
−1)创建子进程失败。② (零)返回到子进程。
对于返回到父进程的值:(正值)返回到父进程,该值包含新创建的子进程的进程ID。
因此,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork
函数返回0,在父进程中,fork
返回新创建子进程的进程ID。用数据结构的知识来理解,其实就相当于链表,进程形成了链表,父进程的fork
函数返回的值指向子进程的进程id,,因为子进程没有子进程,所以其fork
函数返回的值为0。
看下面的代码:
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main(void)
{
fork();
printf(“S\n”);
}
//子进程和父进程都打印出S
运行结果:
注:代码编写和运行的知识可以查看此网址。
https://blog.csdn.net/weixin_45920385/article/details/109373809
进一步对fork
和进程层次结构的了解,看如下代码:
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main(void)
{
fork();
fork();
fork();
printf(“S\n”);
}
运行结果:
分析:
(2)getfork函数
#include<unistd.h>
#include<sys/types.h> //头文件
getfork(void)
getfork
函数返回值是目前进程的进程ID。
例子在第三部分展示。
(3)lockf函数
#include <unistd.h> //头文件
int lockf(int fd, int cmd, int len) //函数原型
lockf
函数对指定区域(有len指示)的资源进行加锁或解锁,以实现进程的同步或互斥。
① fd 是打开文件的文件描述符。
② cmd 是指定要采取的操作的控制值。1是进行锁定,0是解锁。
③ len是要锁定或解锁的连续字节数。
对于这个函数我们主要掌握两个常用命令
1)当len = 0时是个特殊情况,它代表锁定区域从该函数到程序结尾。lockf(1,1,0)
意思是该进程的编号为1,并对进程的资源进行锁定,锁定区域从该函数到程序结尾。
2)lockf(1,0,0)
意思是对编号为1的进程进行解锁,释放资源。
三、具体演示
(1)
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main(void)
{
int pid;
pid=fork();
if(pid < 0)
printf(“error in fork”);
else if(pid == 0)
printf(“I am the child process, my process id is %d\n”,getpid());
else
printf(“I am the parent process, my process id is %d\n”,getpid());
}
运行结果:
分析:
函数fork()
被调用后,若是创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork
函数返回0,在父进程中,fork返回新创建子进程的进程ID。 ,对于子进程,此时
p
i
d
=
0
pid = 0
pid=0,则运行的是第
11
11
11行的输出语句;对于父进程,此时
p
i
d
≠
0
pid ≠ 0
pid=0,则就会运行第
13
13
13行的输出语句 (子进程 ID为父进程 ID加 1)。
(2)在系统中有一个父进程和两个子进程活动。让每个进程在屏幕上显示一个字符:父进程显示字符”a”,子进程分别显示字符”b”和”c”。
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
int p1,p2;
while((p1 = fork()) == -1);
if(p1 == 0)
putchar('b');
else
{
while((p2 = fork()) == -1);
if(p2 == 0)
putchar('c');
else
putchar('a');
}
}
运行结果:
分析:
两个while
语句都是检测fork()
调用是否出错,没有出错则退出循环。所以第一个while
语句循环推出后
p
1
p_1
p1 必定不等于
−
1
-1
−1,当然在父进程
p
1
>
0
p_1 > 0
p1>0,所以直接跳到第二个while
语句,再进行循环,同理也可以知道在其父进程中
p
2
>
0
p_2>0
p2>0,所以接下来先打印
a
a
a,然后回到第一个子进程,此时
p
1
=
0
p_1 = 0
p1=0,所以打印
b
b
b,到下一个子进程,可知
p
2
=
0
p_2 = 0
p2=0,则打印
c
c
c。
(3)实现进程之间的互斥。
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main(void)
{
int p1,p2;
p1 = fork();
if(p1)
{
lockf(1,1,0);
printf("parent\n");
lockf(1,0,0);
}
else
{
lockf(1,1,0);
printf("child\n");
lockf(1,0,0);
}
}
运行结果:
情况一:
情况二:
分析:
可以看到运行结果有两种情况,发现即使没有lockf
函数的影响下也是这两种情况,只体现了父进程和子进程同时执行的特性,而互斥体现在哪里呢,接下来进行分析。首先看情况一,运行fork()
函数;在父进程中,可知
p
1
>
0
p_1 > 0
p1>0进入了第一个代码块中,运行lockf(1,1,0)
把父进程的资源 (同一时刻只可以有一个进程执行输出的资源) 锁住了,因此只能等待父进程把
p
a
r
e
n
t
parent
parent 输出之后然后解锁资源;解锁了资源后子进程再进行对资源加锁输出
c
h
i
l
d
child
child。情况二其实同理,在子进程中,可知
p
1
=
0
p_1 = 0
p1=0,进入而第二个代码块中,运行lockf(1,1,0)
子进程把资源进行加锁,输出
c
h
i
l
d
child
child后,解锁后父进程才能使用输出资源。综上所诉我们可以看出,无论是父进程先执行,还是子进程先执行,都会分别占用资源,只有资源释放了另一个进程才可使用,因此达到了互斥的关系。
需要转载请标明出处
更多推荐
所有评论(0)