谷动谷力

 找回密码
 立即注册
查看: 2028|回复: 1
打印 上一主题 下一主题
收起左侧

【Linux应用开发】fork()函数详解

[复制链接]
跳转到指定楼层
楼主
发表于 2023-8-14 21:13:10 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 sunsili 于 2023-8-14 23:00 编辑

【Linux应用开发】fork()函数详解


1.fork()简介

函数原型:
pid_t fork(void);//pid_t为int类型,进行了重载
pid_t getpid();// 获取当前进程的 pid 值。
pid_t getppid(); //获取当前进程的父进程 pid 值。
用于创建一个进程,所创建的进程复制父进程的代码段/数据段/BSS段/堆/栈等所有用户空间信息;在内核中操作系统重新为其申请了一个PCB,并使用父进程的PCB进行初始化;

如图所示 :我们将A 进程, 也就是调用 fork 的进程称之为父进程, 而新的进程(B 进程)称之为子进程。


关于fork 可以命令,查看详细说明及用法:man 2 fork
NAME
       fork - create a child process

SYNOPSIS
       #include <unistd.h>

       pid_t fork(void);

DESCRIPTION
       fork() creates a new process by duplicating the calling process.  The new process is referred to as the child process.  The calling process is referred to as the parent process.

       The  child  process  and  the parent process run in separate memory spaces.  At the time of fork() both memory spaces have the same content.  Memory writes, file mappings (mmap(2)), and unmappings
       (munmap(2)) performed by one of the processes do not affect the other.

       The child process is an exact duplicate of the parent process except for the following points:

       *  The child has its own unique process ID, and this PID does not match the ID of any existing process group (setpgid(2)).

       *  The child's parent process ID is the same as the parent's process ID.

       *  The child does not inherit its parent's memory locks (mlock(2), mlockall(2)).

       *  Process resource utilizations (getrusage(2)) and CPU time counters (times(2)) are reset to zero in the child.

       *  The child's set of pending signals is initially empty (sigpending(2)).

       *  The child does not inherit semaphore adjustments from its parent (semop(2)).

       *  The child does not inherit process-associated record locks from its parent (fcntl(2)).  (On the other hand, it does inherit fcntl(2) open file description locks and flock(2) locks from its par‐
          ent.)

       *  The child does not inherit timers from its parent (setitimer(2), alarm(2), timer_create(2)).

       *  The  child  does  not inherit outstanding asynchronous I/O operations from its parent (aio_read(3), aio_write(3)), nor does it inherit any asynchronous I/O contexts from its parent (see io_set‐
          up(2)).

       The process attributes in the preceding list are all specified in POSIX.1.  The parent and child also differ with respect to the following Linux-specific process attributes:

       *  The child does not inherit directory change notifications (dnotify) from its parent (see the description of F_NOTIFY in fcntl(2)).

       *  The prctl(2) PR_SET_PDEATHSIG setting is reset so that the child does not receive a signal when its parent terminates.

       *  The default timer slack value is set to the parent's current timer slack value.  See the description of PR_SET_TIMERSLACK in prctl(2).

       *  Memory mappings that have been marked with the madvise(2) MADV_DONTFORK flag are not inherited across a fork().

       *  The termination signal of the child is always SIGCHLD (see clone(2)).

       *  The port access permission bits set by ioperm(2) are not inherited by the child; the child must turn on any bits that it requires using ioperm(2).


2.fork()特性

fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:

在父进程中,fork返回新创建子进程的进程ID;
在子进程中,fork返回0;
如果出现错误,fork返回一个负值;
因此我们可以通过fork返回的值来判断当前进程是子进程还是父进程。(注: fork 调用生成的新进程与其父进程谁先执行不一定,哪个进程先执行要看系统的进程调度策略)

举个例子来解释fpid的值为什么在父子进程中不同:“相当于链表,进程形成了链表,父进程的fpid(p 意味point)指向子进程的进程id, 因为子进程没有子进程,所以其fpid为0.

3, fork()例程


看到这里大家对fork()有个大致了解了,让我们来看个例题:

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <sys/types.h>

  4. int main(int argc, const char *argv[])
  5. {
  6.     int num = 10;
  7.     pid_t pid = fork();
  8.     if(pid==0)
  9.     {
  10.         while (1)
  11.         {
  12.             num = 100;
  13.            printf("The father pid=%d The child pid=%d num=%d\n", getppid(),getpid(), num);
  14.            sleep(3);
  15.         }
  16.     }
  17.     else
  18.     {
  19.         while (1)
  20.         {
  21.             printf("The father pid=%d num=%d\n", getpid(), num);
  22.             sleep(5);
  23.         }
  24.     }

  25.     return 0;
  26. }
复制代码
保存为fork_test.c
  1. gcc  -o fork_test.a fork_test.c
复制代码


运行:
./fork_test.a
The father pid=15131 num=10
The father pid=15131 The child pid=15132 num=100
The father pid=15131 The child pid=15132 num=100
The father pid=15131 num=10
The father pid=15131 The child pid=15132 num=100
The father pid=15131 The child pid=15132 num=100
The father pid=15131 num=10
The father pid=15131 The child pid=15132 num=100

可以看到产生两个pid(进程)



+10
回复

使用道具 举报

沙发
 楼主| 发表于 2023-8-14 21:36:04 | 只看该作者
本帖最后由 sunsili 于 2023-8-14 21:37 编辑

编译时遇到了错误:
gcc -o fork_test.a fork_test.c
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
分析要链接动态库
用命令:
gcc -shared -g -o fork_test.a fork_test.c
/usr/bin/ld: /tmp/cc1wgtVD.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
/tmp/cc1wgtVD.o: error adding symbols: Bad value
collect2: error: ld returned 1 exit status
但又出现问题, 按提示要加参数 fPIC的, 但我没用
重新用原始命令编译:
gcc -o fork_test.a fork_test.c
又OK了

+10
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|深圳市光明谷科技有限公司|光明谷商城|Sunshine Silicon Corpporation ( 粤ICP备14060730号|Sitemap

GMT+8, 2024-5-6 06:39 , Processed in 0.093539 second(s), 44 queries .

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表