二十二、Linux 进程与信号---进程创建(续)
22.2 父子进程操作文件
文件操作由两种模式:
IO 系统调用操作文件
标准C IO 操作文件
看代码:
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h> int g_val = ;//全局变量,存放在数据段 int main(void)
{
int a_val = ;//局部变量,调用的时候存放在栈中
static int s_val = ;//静态变量,存放在数据段
printf("pid: %d", getpid()); FILE *fp = fopen("s.txt", "w");
int fd = open("s_fd.txt", O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG); char *s = "hello world";
ssize_t size = strlen(s) * sizeof(char); /* fork 之前,为父进程调用 */
fprintf(fp, "s: %s, pid: %d\n", s, getpid());//标准 IO 写入(带缓存),针对文件操作的是全缓存
write(fd, s, size); //内核提供的 IO 系统调用(不带缓存) pid_t pid;
pid = fork();//创建子进程
//在 fork 后,会运行两个进程(父进程和子进程)
if(pid < ) {
perror("fork error");
} else if(pid > ) {
//父进程(在父进程中返回的是子进程的 pid)
//父进程执行的代码
g_val = ;
a_val = ;
s_val = ; printf("I am parent process pid is %d, ppid is %d, fork return is %d\n",
getpid(), getppid(), pid);
printf("g_val: %p, a_val: %p, s_val: %p\n", &g_val, &a_val, &s_val);
} else {
//子进程(在子进程中 fork 返回的是0)
//子进程执行的代码
g_val = ;
a_val = ;
s_val = ;
printf("I am child process pid is %d, ppid is %d, fork return is %d\n",
getpid(), getppid(), pid);
printf("g_val: %p, a_val: %p, s_val: %p\n", &g_val, &a_val, &s_val);
} //这里的代码是父子进程都要执行的代码,写入父子进程各自的缓存当中
fprintf(fp, " pid: %d, g_val: %d, a_val: %d, s_val: %d\n", getpid(), g_val, a_val, s_val);
sleep(); return ;
}
编译运行后,两个文件都生成了。

父进程文件 s.txt

子进程文件 s_fd.txt

系统调用不经过缓存,执行 write 后就直接写进了文件当中,标准IO是写入缓存了。
创建的缓存是在堆当中的,我们的代码是在 fork 之前,那么缓存就在父进程的虚拟空间的堆当中,当 fork 之后,子进程会 COPY 一份父进程的堆空间。
同样 fork 之后也由一份写入缓存的 fprintf,此时是各自写入各自的缓存,在结束的时候父子进程都会清缓存,都会写入 fp 当中

22.3 操作文件时的内核结构体变化
- 子进程只继承父进程的文件描述符表,不继承但共享文件表项和 i-node
- 父进程创建一个子进程后,文件表项中的引用计数器加1 变成 2,当父进程作 close 操作后,计数器减 1,子进程还是可以使用文件表项(即子进程还是可以操作文件),只有当计数器为 0 时,才会释放文件表项。

运行 fork:

例子:父进程调节文件偏移量,子进程写入
process_append.c
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> int main(int argc, char *argv[])
{
if(argc < )
{
fprintf(stderr, "usage: %s file\n", argv[]);
exit();
} int fd = open(argv[], O_WRONLY);
if(fd < )
{
perror("open error");
exit();
} pid_t pid = fork();
if(pid < )
{
perror("fork error");
exit();
}
else if(pid > )
{//父进程将文件偏移量调整到文件尾部
if(lseek(fd, 0L, SEEK_END) < ) {
perror("lseek error");
exit();
}
}
else
{//子进程从文件尾部追加内容
char *str = "hello child";
ssize_t size = strlen(str) * sizeof(char); sleep();//保证父进程调节偏移量成功 //从用户角度去看,子进程会复制一份父进程的文件描述符,都指向同一个文件
//从内核角度区看,文件描述符表复制了一份,文件描述符表指向了同一个文件表项,都指向同一个文件
//此处的 fd 是从父进程中复制过来的
//但和父进程中的 fd 都是指向同一个文件的
if(write(fd, str, size) != size) {
perror("write error");
exit();
}
} printf("pid ; %d finish\n", getpid());
sleep(); //父子进程都要去关闭文件描述符
close(fd); return ;
}
编译运行:


二十二、Linux 进程与信号---进程创建(续)的更多相关文章
- Linux学习之CentOS(二十六)--Linux磁盘管理:LVM逻辑卷的创建及使用
在上一篇随笔里面 Linux学习之CentOS(二十五)--Linux磁盘管理:LVM逻辑卷基本概念及LVM的工作原理,详细的讲解了Linux的动态磁盘管理LVM逻辑卷的基本概念以及LVM的工作原理, ...
- JAVA基础知识总结:一到二十二全部总结
>一: 一.软件开发的常识 1.什么是软件? 一系列按照特定顺序组织起来的计算机数据或者指令 常见的软件: 系统软件:Windows\Mac OS \Linux 应用软件:QQ,一系列的播放器( ...
- 智课雅思词汇---二十二、-al即是名词性后缀又是形容词后缀
智课雅思词汇---二十二.-al即是名词性后缀又是形容词后缀 一.总结 一句话总结: 后缀:-al ②[名词后缀] 1.构成抽象名词,表示行为.状况.事情 refusal 拒绝 proposal 提议 ...
- [分享] IT天空的二十二条军规
Una 发表于 2014-9-19 20:25:06 https://www.itsk.com/thread-335975-1-1.html IT天空的二十二条军规 第一条.你不是什么都会,也不是什么 ...
- Bootstrap <基础二十二>超大屏幕(Jumbotron)
Bootstrap 支持的另一个特性,超大屏幕(Jumbotron).顾名思义该组件可以增加标题的大小,并为登陆页面内容添加更多的外边距(margin).使用超大屏幕(Jumbotron)的步骤如下: ...
- Web 前端开发精华文章推荐(HTML5、CSS3、jQuery)【系列二十二】
<Web 前端开发精华文章推荐>2014年第一期(总第二十二期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML ...
- 二十二、OGNL的一些其他操作
二十二.OGNL的一些其他操作 投影 ?判断满足条件 动作类代码: ^ $ public class Demo2Action extends ActionSupport { public ...
- WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇]
原文:WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇] 在[上篇]中,我们分别站在消息交换和编程的角度介绍了SOAP Fault和FaultException异常.在服务执行过 ...
- VMware vSphere 服务器虚拟化之二十二桌面虚拟化之创建View Composer链接克隆的虚拟桌面池
VMware vSphere 服务器虚拟化之二十二桌面虚拟化之创建View Composer链接克隆的虚拟桌面池 在上一节我们创建了完整克隆的自动专有桌面池,在创建过程比较缓慢,这次我们将学习创建Vi ...
- Bootstrap入门(二十二)组件16:列表组
Bootstrap入门(二十二)组件16:列表组 列表组是灵活又强大的组件,不仅能用于显示一组简单的元素,还能用于复杂的定制的内容. 1.默认样式列表组 2.加入徽章 3.链接 4.禁用的列表组 5. ...
随机推荐
- SP8791 DYNALCA - Dynamic LCA 解题报告
SP8791 DYNALCA - Dynamic LCA 有一个森林最初由 \(n (1 \le n \le 100000)\) 个互不相连的点构成 你需要处理以下操作: link A B:添加从顶点 ...
- LOJ#6283. 数列分块入门 7
对于每个区间先乘在加,如果我修改的是部分的块,我就需要把现这个块的add和mul标记全部放下去,然后再更新. #include<map> #include<set> #incl ...
- NOIP2017题解
T1小凯的疑惑 小凯手中有两种面值的金币,两种面值均为正整数且彼此互素.每种金币小凯都有 无数个.在不找零的情况下,仅凭这两种金币,有些物品他是无法准确支付的.现在小 凯想知道在无法准确支付的物品中, ...
- 【mysql】mysql尾部空格
mysql 字段为varchar类型的在查询时候胡忽略尾部空格. 先看表结构 插入一条数据包含空格 在查询是可以查到的 所有在插入数据的时候要对插入字段的数据处理下,php可以用函数trim()去掉两 ...
- MyBatis深入浅出--入门
mybatis概述 mybatis简介 MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架. MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集. ...
- CodeForces 407C 组合数学(详解)
题面: http://codeforces.com/problemset/problem/407/C 一句话题意:给一个长度为n的序列g,m次操作,每次操作(l,r,k)表示将g[l]~g[r]的每个 ...
- QML学习笔记(六)- 简单计时器和定时器
做一个简单的qml计时器和定时器,左键触发计时,右键触发定时 GitHub:八至 作者:狐狸家的鱼 本文链接:QML学习笔记(六)- 简单计时器和定时器 左键点击按钮,触发计时器,中键可以暂停计时,同 ...
- tyvj/joyoi 1043 表达式计算4
这题怎么这么毒瘤... 一开始我想转后缀表达式来计算,后来发现有负数...弃疗. 递归求解又发现会有多余括号,我觉得不行... 实在是毒瘤啊! #include <cstdio> #inc ...
- redis设置最大内存
- 第十三节,使用带有全局平均池化层的CNN对CIFAR10数据集分类
这里使用的数据集仍然是CIFAR-10,由于之前写过一篇使用AlexNet对CIFAR数据集进行分类的文章,已经详细介绍了这个数据集,当时我们是直接把这些图片的数据文件下载下来,然后使用pickle进 ...