**《Linux/Unix系统编程手册》读书笔记24章**

news2024/11/16 9:41:25

D 24章 进程的创建 425
24.1 fork()、exit()、wait()以及execve()的简介 425
. 系统调用fork()允许父进程创建子进程
. 库函数exit(status)终止进程,将进程占用的所有资源归还内核,交其进行再次分配。库函数exit()位于系统调用_exit()之上。在调用fork()之后, 父,子进程中一般只有一个会通过调用exit()退出,而另一个进程则应适用_exit()终止。
在这里插入图片描述

#define _BSD_SOURCE
#include “tlpi_hdr.h”

int main(int argc, char *argv[]){
int istack = 222;

switch (vfork()) {
case -1:
    errExit("vfork");

case 0:             /* Child executes first, in parent's memory space */
    sleep(3);                   /* Even if we sleep for a while,
                                   parent still is not scheduled */
    write(STDOUT_FILENO, "Child executing\n", 16);
    istack *= 3;                /* This change will be seen by parent */
    _exit(EXIT_SUCCESS);

default:            /* Parent is blocked until child exits */
    write(STDOUT_FILENO, "Parent executing\n", 17);
    printf("istack=%d\n", istack);
    exit(EXIT_SUCCESS);
}

}
(base) wannian07@wannian07-PC:~/Desktop/std/linux prog$ gcc t_vfork.c -o t_vfork error_functions.c curr_time.c
(base) wannian07@wannian07-PC:~/Desktop/std/linux prog$ ./t_vfork
Child executing
Parent executing
istack=666
提示:除非速度绝对重要的场合,新程序应当舍弃vfork()而取用 fork()
. 系统调用wait(&status)目的:1. 子进程尚未调用exit()终止,那么wait()会挂起父进程直至子进程终止。2. 子进程的终止状态通过wait()的status参数返回。
. 系统调用execve(pathname, argv, envp)到当前进程的内存。

FBReader也叫E-book Viewer,可以安装在ubuntu系统中来打开mobi文件。安装方式如下,终端执行:sudo apt install fbreader
24.2 创建新进程:fork() 427
创建多个进程是任务分解行之有效的方法。例如,网络服务器进程可在侦听客户端请求的同时,为处理每一请求而创建一新的子进程,与此同时,服务器进程会继续侦听更多的客户端连接请求。好处,简化应用程序的设计,同时提高了系统的并发性。
子进程的栈,数据,以及栈段开始时是对父进程内存相应各部分完全复制。执行fork()后,每个进程均可修改各自的栈,数据,堆段中的变量。
fork()通过返回值来区分父, 子进程。fork()在子进程中返回0。
子进程调用 getpid() 获取自身的进程。
父进程调用 getppid() 获取进程。
无法创建fork()子进程,返回-1。原因:a. 进程数量要么超出了系统针对此真实用户在进程数量上所施加的限制。b. 触及允许该系统创建的最大进程这一系统级上限。
#include “curr_time.h” /* Declaration of currTime() */
#include “tlpi_hdr.h”
#include “error_functions.h”
#include “curr_time.h”

static int idata = 111; /* Allocated in data segment */
int main(int argc, char argv[]){
int istack = 222; /
Allocated in stack segment */
pid_t childPid;

switch (childPid = fork()) {
case -1:
    errExit("fork");

case 0:
    idata *= 3;
    istack *= 3;
    break;

default:
    sleep(3);                   /* Give child a chance to execute */
    break;
}
/* Both parent and child come here */
printf("PID=%ld %s idata=%d istack=%d\n", (long) getpid(),
        (childPid == 0) ? "(child) " : "(parent)", idata, istack);
exit(EXIT_SUCCESS);

}
(base) wannian07@wannian07-PC:~/Desktop/std/linux prog$ gcc t_fork.c -o t_fork error_functions.c curr_time.c
(base) wannian07@wannian07-PC:~/Desktop/std/linux prog$ ./t_fork
PID=4372 (child) idata=333 istack=666
PID=4371 (parent) idata=111 istack=222

		**24.2.1 父、子进程间的文件共享 428** 

#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include “tlpi_hdr.h”

int main(int argc, char *argv[]){
int fd, flags;
char template[] = “/tmp/testXXXXXX”;

setbuf(stdout, NULL);                   /* Disable buffering of stdout */

/* Open a temporary file, set its file offset to some arbitrary value,
   and change the setting of one of the open file status flags. */

fd = mkstemp(template);
if (fd == -1)
    errExit("mkstemp");

printf("File offset before fork(): %lld\n",
        (long long) lseek(fd, 0, SEEK_CUR));

flags = fcntl(fd, F_GETFL);
if (flags == -1)
    errExit("fcntl - F_GETFL");
printf("O_APPEND flag before fork() is: %s\n",
        (flags & O_APPEND) ? "on" : "off");

switch (fork()) {
case -1:
    errExit("fork");

case 0:     /* Child: change file offset and status flags */
    if (lseek(fd, 1000, SEEK_SET) == -1)
        errExit("lseek");

    flags = fcntl(fd, F_GETFL);         /* Fetch current flags */
    if (flags == -1)
        errExit("fcntl - F_GETFL");
    flags |= O_APPEND;                  /* Turn O_APPEND on */
    if (fcntl(fd, F_SETFL, flags) == -1)
        errExit("fcntl - F_SETFL");
    _exit(EXIT_SUCCESS);

default:    /* Parent: can see file changes made by child */
    if (wait(NULL) == -1)
        errExit("wait");                /* Wait for child exit */
    printf("Child has exited\n");

    printf("File offset in parent: %lld\n",
            (long long) lseek(fd, 0, SEEK_CUR));

/*
通常将存放文件偏移量的数据类型off_t实现为一个有符号的长整型,在32位体系架构中,文件大小为2GB限制,在64位体系架构中,限额远远超出目前的磁盘容量,无实际意义。_FILE_OFFSET_BITS宏,要求程序代码编写必须规范。声明用于放置文件偏移量的变量,应正确地使用off_t, 而不能使用“原生”的C语言整型。
*/
flags = fcntl(fd, F_GETFL);
if (flags == -1)
errExit(“fcntl - F_GETFL”);
printf(“O_APPEND flag in parent is: %s\n”,
(flags & O_APPEND) ? “on” : “off”);
exit(EXIT_SUCCESS);
}
}
(base) wannian07@wannian07-PC:~/Desktop/std/linux prog$ gcc fork_file_sharing.c -o fork_file_sharing error_functions.c curr_time.c
(base) wannian07@wannian07-PC:~/Desktop/std/linux prog$ ./fork_file_sharing
File offset before fork(): 0
O_APPEND flag before fork() is: off
Child has exited
File offset in parent: 1000
O_APPEND flag in parent is: on

		****24.2.2 fork()的内存语义 430**** 

在这里插入图片描述

	****24.3 系统调用vfork() 433** 
	**24.4 fork()之后的竞争条件(Race Condition) 434**** 

#include <sys/wait.h>
#include “tlpi_hdr.h”

int main(int argc, char *argv[]){
int numChildren, j;
pid_t childPid;

if (argc > 1 && strcmp(argv[1], "--help") == 0)
    usageErr("%s [num-children]\n", argv[0]);
numChildren = (argc > 1) ? getInt(argv[1], GN_GT_0, "num-children") : 1;

setbuf(stdout, NULL); /* Make stdout unbuffered */

for (j = 0; j < numChildren; j++) {
    switch (childPid = fork()) {
    case -1:
        errExit("fork");

    case 0:
        printf("%d child\n", j);
        _exit(EXIT_SUCCESS);

    default:
        printf("%d parent\n", j);
        wait(NULL);                 /* Wait for child to terminate */
        break;
    }
}

exit(EXIT_SUCCESS);

}
(base) wannian07@wannian07-PC:~/Desktop/std/linux prog$ gcc fork_whos_on_first.c -o fork_whos_on_first error_functions.c curr_time.c get_num.c //要求只产生一个进程
(base) wannian07@wannian07-PC:~/Desktop/std/linux prog$ ./fork_whos_on_first 1
0 parent
0 child

	****24.5 同步信号以规避竞争条件 436**** 

#include <signal.h>
#include “curr_time.h” /* Declaration of currTime() */
#include “tlpi_hdr.h”
#include “error_functions.h”
#include “curr_time.h”

#define SYNC_SIG SIGUSR1 /* Synchronization signal */

static void /* Signal handler - does nothing but return */
handler(int sig)
{
}

int
main(int argc, char *argv[])
{
pid_t childPid;
sigset_t blockMask, origMask, emptyMask;
struct sigaction sa;

setbuf(stdout, NULL);               /* Disable buffering of stdout */

sigemptyset(&blockMask);
sigaddset(&blockMask, SYNC_SIG);    /* Block signal */
if (sigprocmask(SIG_BLOCK, &blockMask, &origMask) == -1)
    errExit("sigprocmask");

sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sa.sa_handler = handler;
if (sigaction(SYNC_SIG, &sa, NULL) == -1)
    errExit("sigaction");

switch (childPid = fork()) {
case -1:
    errExit("fork");

case 0: /* Child */

    /* Child does some required action here... */

    printf("[%s %ld] Child started - doing some work\n",
            currTime("%T"), (long) getpid());
    sleep(2);               /* Simulate time spent doing some work */

    /* And then signals parent that it's done */

    printf("[%s %ld] Child about to signal parent\n",
            currTime("%T"), (long) getpid());
    if (kill(getppid(), SYNC_SIG) == -1)
        errExit("kill");

    /* Now child can do other things... */

    _exit(EXIT_SUCCESS);

default: /* Parent */

    /* Parent may do some work here, and then waits for child to
       complete the required action */

    printf("[%s %ld] Parent about to wait for signal\n",
            currTime("%T"), (long) getpid());
    sigemptyset(&emptyMask);
    if (sigsuspend(&emptyMask) == -1 && errno != EINTR)
        errExit("sigsuspend");
    printf("[%s %ld] Parent got signal\n", currTime("%T"), (long) getpid());

    /* If required, return signal mask to its original state */

    if (sigprocmask(SIG_SETMASK, &origMask, NULL) == -1)
        errExit("sigprocmask");

    /* Parent carries on to do other things... */

    exit(EXIT_SUCCESS);
}

}

(base) wannian07@wannian07-PC:~/Desktop/std/linux prog$ gcc fork_sig_sync.c -o fork_sig_sync error_functions.c curr_time.c
(base) wannian07@wannian07-PC:~/Desktop/std/linux prog$ ./fork_sig_sync
[15:21:36 4518] Parent about to wait for signal
[15:21:36 4519] Child started - doing some work
[15:21:38 4519] Child about to signal parent
[15:21:38 4518] Parent got signal
跟原书本P437 不同哦

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1809597.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

开发小Tips:切换淘宝,腾讯,官方,yarn,cnpm镜像源,nrm包管理工具的具体使用方式(方便切换镜像源)

由于开发中经常要下载一些软件或者依赖&#xff0c;且大多数的官方源的服务器都在国外&#xff0c;网速比较慢&#xff0c;国内为了方便&#xff0c;国内一些大厂就建立一些镜像&#xff0c;加快下载速度。 1.各大镜像源的切换&#xff1a; 切换淘宝镜像源&#xff1a; npm …

基于51单片机的MQ-2烟雾报警设计

随着现代家庭用火、用电量的增加,家庭烟雾发生的频率越来越高。烟雾报警器也随之被广泛应用于各种场合。本课题所研究的无线多功能烟雾报警器采用STC89C51为核心控制器,利用气体传感器MQ-2、ADC0832模数转换器、DS18B20温度传感器等实现基本功能。通过这些传感器和芯片,当环…

圆 高级题目

上边的文章发了圆的初级题目&#xff0c;这篇来发高级 参考答案&#xff1a;ACCBBBBCDC

嵌入式作业6

1、利用SysTick定时器编写倒计时程序&#xff0c;如初始设置为2分30秒&#xff0c;每秒在屏幕上输出一次时间&#xff0c;倒计时为0后&#xff0c;红灯亮&#xff0c;停止屏幕输出&#xff0c;并关闭SysTick定时器的中断。 2、利用RTC显示日期&#xff08;年月日、时分秒&…

[C++数据结构之看懂就这一篇]图(上)

&#x1f4da;博客主页&#xff1a;Zhui_Yi_&#x1f50d;&#xff1a;上期回顾&#xff1a;JAVA面向对象&#xff08;上&#xff09;❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️&#x1f387;追当今朝…

币安用户达2亿,代币BNB创新高,赵长鹏成“美国最富囚犯” 苹果迈向AI新纪元:芯片、应用与大模型三线作战

赵长鹏坐牢第一个月&#xff0c;越坐越富。 在币安联合创始人赵长鹏入狱服刑的第一个月&#xff0c;币安代币BNB创下了历史新高&#xff0c;使得赵长鹏成为美国联邦监狱中史上“最富囚犯”。与此同时&#xff0c;币安用户数量也到达2亿“里程碑”。 根据CoinGecko的数据&…

从河流到空气,BL340工控机助力全面环保监测网络构建

在环保监测领域&#xff0c;智能化、高效率的监测手段正逐步成为守护绿水青山的新常态。其中&#xff0c;ARMxy工业计算机BL340凭借其强大的处理能力、高度的灵活性以及广泛的兼容性&#xff0c;在水质监测站、空气质量检测、噪音污染监控等多个环保应用场景中脱颖而出&#xf…

解决阿里云的端口添加安全组仍然无法扫描到

发现用线上的网站扫不到这个端口&#xff0c;这个端口关了&#xff0c;但是没有更详细信息了 我用nmap扫了一下我的这个端口&#xff0c;发现主机是活跃的&#xff0c;但是有防火墙&#xff0c;我们列出云服务器上面的这个防火墙list&#xff0c;发现确实没有5566端口 参考&a…

Java(十七)---ArrayList的使用

文章目录 前言1.ArrayList的简介2. ArrayList使用2.1.ArrayList的构造2.2.ArrayList的扩容机制(JDK17) 3.ArrayList的常见操作4. ArrayList的具体使用4.1.[杨辉三角](https://leetcode.cn/problems/pascals-triangle/description/)4.2.简单的洗牌游戏 5.ArrayList的问题及思考 …

RocketMq详解:二、SpringBoot集成RocketMq

在上一章中我们对Rocket的基础知识、特性以及四大核心组件进行了详细的介绍&#xff0c;本章带着大家一起去在项目中具体的进行应用&#xff0c;并设计将其作为一个工具包只提供消息的分发服务和业务模块进行解耦 在进行本章的学习之前&#xff0c;需要确保你的可以正常启动和…

每天写java到期末考试(6.10)--java小项目01

实现项目任务 java类 package java1;import java.util.ArrayList; import java.util.Scanner;public class Test {public static void main(String[] args) {//8.创建一个集合&#xff0c;用于存放相同个体&#xff0c;一个个添加&#xff0c;注意作用范围&#xff0c;将数组放…

为Nanopi m1交叉编译opencv

为Nanopi m1交叉编译opencv 一、下载交叉编译器 根据之前的博客进行 二、下载opencv和必要库 sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-devgit clone https://github.com/opencv/opencv.git cd opencv三、进行编…

纯理论容器实现的原理

近期在复习容器的原理&#xff0c;希望这篇文章可以帮助到大家。 一、什么是容器&#xff1f; 容器本质上就是主机上的一个进程。这个进程拥有自己的用户空间并且和主机共享内核空间。 容器内的进程可以通过系统调用与内核进行交互&#xff0c;使用内核提供的各种功能和资源。…

达梦数据库搭建守护集群

前言 DM 数据守护&#xff08;Data Watch&#xff09;是一种集成化的高可用、高性能数据库解决方案&#xff0c;是数据库异地容灾的首选方案。通过部署 DM 数据守护&#xff0c;可以在硬件故障&#xff08;如磁盘损坏&#xff09;、自然灾害&#xff08;地震、火灾&#xff09…

速度位置规划实现精确定位的问题

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

NettyのBufferChannelSelector用法

这一篇介绍Buffer&Channel&Selector的常见API使用案例 1、Buffer 1.1、从Buffe中读取/写入 以ByteBuffer为例。Buffer需要和Channel结合使用&#xff08;在上一篇中提到&#xff0c;通道是数据传输的载体&#xff0c;缓冲区是数据的临时存储区&#xff09;。 那么如何…

44【Aseprite 作图】樱花丸子——拆解

1 枝干 2 花朵&#xff1a;其实只要形状差不多都行&#xff0c;有三个颜色&#xff0c;中间花蕊颜色深一点&#xff0c;中间花蕊外的颜色偏白&#xff1b;不透明度也可以改一下&#xff0c;就变成不同颜色 3 丸子 最外层的颜色最深&#xff0c;中间稍浅&#xff0c;加一些高光…

解决福昕风腾PDF套装无法打印在线电子签章的方法

使用福昕风腾PDF套装打印在线电子签章文件时发现&#xff0c;在线盖的电子印章和签名却打印不出来&#xff0c;后现发现&#xff0c;按图中选项选择“文档”&#xff0c;即可完整打印文件内容及电子签章。留印。

【2023】LitCTF

LitCTF2023&#xff08;复现&#xff09; Web&#xff1a; 1、我Flag呢&#xff1f; ​ ctrlu 读取源码&#xff0c;在最后发现了flag&#xff1a; <!--flag is here flagNSSCTF{3d5218b9-4e24-4d61-9c15-68f8789e8c48} -->2、PHP是世界上最好的语言&#xff01;&…

Spring AOP 基于注解实现用户权限校验

主要注解 interface&#xff1a;继承了 Annotation 接口的自定义注解&#xff0c;定义注释类型。 Target&#xff1a;表示这个注解可以应用的地方&#xff0c;此处做权限校验是用在方法上的&#xff0c;所以此处的值为 Target(ElementType.METHOD) …