晚上好,继续记录我的学习心得。

当你厌倦了自己的目标时,怎样继续保持专注?

误区:
成功人士说的都是自己如何“满怀热情”去努力实现他们的目标。不管是在商业、体育还是艺术界,我们听到的都是“一切都归结于激情”或者“你必须真的渴望得到它”之类的说法。

这让我们认为成功人士会有无限的激情,如果我们感到自己激情消退了,仿佛说明了我们不如他们,这让人很沮丧。

事实是:
他们没把话说完整。成功人士也会和普通人一样感到激情消退,这是任何人都无法逃脱的。熟能生巧。你练习的次数越多,它就变得越无聊,越像是机械地重复。

成功的最大威胁不是失败,而是倦怠
我们厌倦了好习惯,因为它们不再让我们开心。就好像写作一样,长期来看会给我带来好的结果,但是总会有那么几天我也会感觉写作是枯燥的。

成功人士更强大的地方在于:
尽管感到枯燥乏味,他们仍想办法坚持下去。

对抗枯燥感的小技巧:
在开始做自己不不想做的事情时: 先一边听音乐一边干,15分钟后再摘下耳机。必须控制时间,因为听得越多,音乐给你带来的满足感就会越少。

以下是正文,先明确一下正文的目的:

  • 举例说明 Linux 下父子进程如何使用管道进行通讯。

目录:

一、概述- 1. IPC 工具分类- 2. 什么是管道- 3. 管道的 2 个局限性- 4. 管道是最常用的 IPC- 5. 使用 pipe() 创建管道二、一个简单的例子 (simple_pipe.c)- 1. 代码分析- 2. 相关要点三、参考书籍四、欢迎加入我的微信群

一、概述

1. IPC 工具分类

  • 通信类 (communication):这类工具关注进程之间的数据交换。

  • 同步类 (synchronization):这类工具关注进程和线程操作之间的同步。

  • 信号类 (signal):尽管信号的主要作用并不在此,但在特定场景下仍然可以将它作为一种同步技术。更罕见的是信号还可以作为一种通信技术:信号编号本身是一种形式的信息,并且可以在实时信号上绑定数据。

2. 什么是管道

当从一个进程连接数据流到另一个进程时,我们使用术语管道 (pipe),也叫无名管道 (unnamed pipe)。通常是把一个进程的输出通过管道连接到另一个进程的输入。

管道是 UNIX 系统最古老的 IPC ,所有 UNIX 系统都提供这种通信机制。

3. 管道的 2 个局限性

  • 历史上,它是半双工的 (即数据只能在一个方向上流动)。现在,某些系统提供全双工管道,但是为了可移植性,我们不应预先假定系统支持全双工管道。

  • 管道只能在具有公共祖先的两个进程之间使用。通常,一个管道由一个进程创建,在进程调用 fork 之后,这个管道就能在父进程和子进程之间使用了。

4. 尽管有这 2 个局限性,半双工管道仍是最常用的 IPC

每当在管道中键入一个命令序列,让 shell 执行时,shell 都会为每一条命令单独创建一个进程,然后用管道将前一条命令进程的标准输出与后一条命令的标准输入相连接。shell 负责安排两个命令的标准输入和标准输出:

  • cmd1 的标准输入来自终端键盘;

  • cmd1 的标准输出传递给 cmd2,作为它的标准输入;

  • cmd2 的标准输出连接到终端屏幕;

shell 所做的工作实际上是对标准输入和标准输出流进行了重新连接,使数据流从键盘输入通过两个命令最终输出到屏幕上。

以 "$ ls | wc -l" 为例:

5. 使用 pipe() 创建管道

$ man 2 pipe
NAMEpipe, pipe2 - create pipe
SYNOPSIS#include <unistd.h>int pipe(int filedes[2]);

成功的 pipe() 调用会在数组 filedes 中返回两个打开的文件描述符:一个表示管道的读取端 (filedes[0]),另一个表示管道的写入端 (filedes[1])。

与所有文件描述符一样,可以使用 read() 和 write() 在管道上执行 I/O 操作。一旦向管道的写入端写入数据之后立即就能从管道的读取端读取数据。

二、一个简单的例子 (simple_pipe.c)

1. 代码分析

下面的程序演示了如何将管道用于父进程和子进程之间的通信:

int main(int argc, char *argv[])
{int pfd[2];char buf[BUF_SIZE];ssize_t numRead;if (argc != 2 || strcmp(argv[1], "--help") == 0)usageErr("%s string\n", argv[0]);if (pipe(pfd) == -1)    /* Create the pipe */errExit("pipe");switch (fork()) {case -1:errExit("fork");case 0:             /* Child  - reads from pipe */if (close(pfd[1]) == -1)            /* Write end is unused */errExit("close - child");for (;;) {              /* Read data from pipe, echo on stdout */numRead = read(pfd[0], buf, BUF_SIZE);if (numRead == -1)errExit("read");if (numRead == 0)break;                      /* End-of-file */if (write(STDOUT_FILENO, buf, numRead) != numRead)fatal("child - partial/failed write");}// cleanup...default:            /* Parent - writes to pipe */if (close(pfd[0]) == -1)            /* Read end is unused */errExit("close - parent");if (write(pfd[1], argv[1], strlen(argv[1])) != strlen(argv[1]))fatal("parent - partial/failed write");if (close(pfd[1]) == -1)            /* Child will see EOF */errExit("close");wait(NULL);                         /* Wait for child to finish */exit(EXIT_SUCCESS);}
}

运行效果:

$ ./simple_pipe 'msg from parent'
msg from parent

单个进程中的管道几乎没有任何用处。一般来讲都是使用管道让两个进程进行通信。为了让两个进程通过管道进行连接,在调用完 pipe() 之后可以调用 fork(),子进程会继承父进程的文件描述符的副本:

虽然父进程和子进程都可以从管道中读取和写入数据,但一般不这么使用管道。通常,在 fork() 之后,其中一个进程应该立即关闭管道的写入端的描述符,另一个则应该关闭读取端的描述符。在上面的例子中,父进程向子进程传输数据,所以它关闭了管道的读取端的描述符 filedes[0],而子进程则关闭管道的写入端的描述符 filedes[1]:

2. 相关要点

  1. 父子进程从同一个管道中读取和写入数据这种做法不好的原因是:

  • 如果两个进程同时试图从管道中读取数据,那么就无法确定哪个进程会首先读取成功——两个进程竞争数据了,即会产生竞争。

  • 使用管道进行双向通信更加简单的方法是:创建两个管道,在两个进程之间发送数据的两个方向上各使用一个。

  • 管道可以用于任意两个(或更多)相关进程之间的通信,只要在创建子进程的系列 fork() 调用之前通过一个共同的祖先进程创建管道即可。

  • 关闭未使用管道文件描述符对于正确使用管道非常重要的:

    • 当 read 一个写入端 (write end) 已被关闭的管道时,在所有数据都被读取后,read 会返回 0,这时读取进程就知道文件已结束了。

    • 如果读取进程没有关闭管道的写入端,那么在其他进程关闭了写入描述符之后,读取进程也不会看到文件结束,即使它读完了管道中的所有数据。

    • 当 write 一个读取端已被关闭的管道,内核会向写入进程发送一个SIGPIPE 信号。在默认情况下,这个信号会杀死进程。但进程可以捕获或忽略该信号,这时管道上的 write() 操作因 EPIPE 错误而失败。收到SIGPIPE 信号 和获得 EPIPE 错误对于可以起到标示管道状态的作用。

  • 在写管道时,常量 PIPE_BUF 规定了内核的管道缓冲区大小。

    • 如果对管道调用 write(),而且要求写的字节数小于等于 PIPE_BUF,则此操作不会与其他进程对同一管道的 write 操作交叉进行。

    • 如果有多个进程同时写一个管道,且要求写入的字节数超过 PIPE_BUF,则所写的数据可能会与其他进程所写的数据交错在一起。

    三、相关参考

    • 《UNIX 环境高级编程 - 15.2 管道》

    • 《Linux / UNIX 系统编程手册 - 44.管道和FIFO》

    • 《Linux 程序设计 - 13.进程间通信:管道》

    • 《UNIX-Linux编程实践教程 - 10.I/O 重定向和管道》

    更多值得学习的知识点:

    • 将管道作为一种进程同步的方法;

    • 使用管道连接过滤器;

    • 通过管道与 shell 命令进行通信:popen();

    • 管道和 stdio 缓冲;

    • 命名管道:FIFO; ...

    鉴于大多数人的注意力无法在一篇文章里上集中太久,更多的内容请大家自行去阅读吧,不是自己理解到的东西是消化不了的。有机会的话我会把更多的读书心得放在后面的文章。

    你和我各有一个苹果,如果我们交换苹果的话,我们还是只有一个苹果。但当你和我各有一个想法,我们交换想法的话,我们就都有两个想法了。如果你也对 嵌入式系统和开源软件 感兴趣,并且想和更多人互相交流学习的话,请关注我的公众号:嵌入式 Hacker,一起来学习吧,无论是 关注或转发 , 还是赏赐,都是对作者莫大的支持,感谢 各位的大拇指「在看」 ,,祝工作顺利,家庭和睦~

      推荐阅读:

    专辑|Linux文章汇总

    专辑|程序人生

    专辑|C语言

    嵌入式Linux

    微信扫描二维码,关注我的公众号

Linux系统编程-管道入门相关推荐

  1. Linux系统编程-信号入门2

    早,继续记录我的学习心得. 分享一个关于机械练习和有目的练习的看法. 机械的练习: 只是埋头干!我刚刚挥起球拍,努力去击球.我刚刚听到了那些数字,想办法去记住.我刚刚看到了那些数学题,正试着解答. 有 ...

  2. Linux系统编程-信号入门3

    早,继续记录我的学习心得. 机械的练习: 只是埋头干!我一直在挥着球拍,努力去击球.我一直在看这道数学题,正试着解答.我一直在重复写代码,试图成为技术大牛. 有准确目的的练习: 意味着要比机械的练习更 ...

  3. 一文带你Linux系统编程入门

    文件和文件系统 文件是linux系统中最重要的抽象,大多数情况下你可以把linux系统中的任何东西都理解为文件,很多的交互操作其实都是通过文件的读写来实现的. 文件描述符 在linux内核中,文件是用 ...

  4. 【Linux】Linux系统编程(入门与系统编程)(一)(环境搭建、常见指令以及权限理解)

    目录 linux系统编程 : 1.推动技术进步的基本模式 2.理解操作系统的发展 Linux 背景介绍 UNIX发展的历史: Linux发展历史 开源 Linux的发行版本: a.技术角度 b.商业化 ...

  5. 【Linux系统编程】进程间通信之无名管道

    00. 目录 文章目录 00. 目录 01. 管道概述 02. 管道创建函数 03. 管道的特性 04. 管道设置非阻塞 05. 附录 01. 管道概述 管道也叫无名管道,它是是 UNIX 系统 IP ...

  6. 【Linux系统编程学习】匿名管道pipe与有名管道fifo

    此为牛客Linux C++和黑马Linux系统编程课程笔记. 0. 关于进程通信 Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间.任何一个进程的全局变量在另一个进程中都看不到 ...

  7. 【学习笔记】Linux 系统编程入门

    Linux 系统编程入门 静态库与动态库 静态库命名规则 静态库的制作 静态库使用 动态库制作 动态库使用 加载动态库 静态库的优缺点 动态库的优缺点 Makefile 文件命名 工作原理 变量 模式 ...

  8. Linux系统编程- 无名管道(匿名管道)

    无名管道作为Linux进程间通讯,我们这里把理论和实际结合起来说明. 1.什么是管道 管道,英文位pipe,在学习linux系统编程一个重要概念.它的发明人是道格拉斯.麦克罗伊,这位也是UNIX上早期 ...

  9. 入门Linux系统编程--网络编程

    文章目录 一.网络编程 1.socket服务端代码实现(无连接客户端) 6.socket服务端代码实现(连接客户端) 7.socket客户端代码实现 8.实现双方聊天 9.多方消息收发 二.往期文章 ...

最新文章

  1. 通过regedt查看计算机密码,win10系统通过注册表设置定时更换密码提醒的处理步骤...
  2. Gartner 2019 年供应链技术八大趋势:AI、高级分析、物联网、RPA、自主设备、数字孪生...
  3. 迷茫的不是青春,是你们回望青春时失焦的眼神。
  4. wpf控件设计时支持(2)
  5. python录制视频和声音_python录制系统声音
  6. 虚拟网络编辑器的知识和出现的一些问题(没有VMnet0或VMnet8)
  7. UltraEdit不高亮解决办法
  8. ACE反应器(Reactor)模式
  9. 站在BERT肩膀上的NLP新秀们:XLMs、MASS和UNILM
  10. 分别用ToolBar和自定义导航栏实现沉浸式状态栏
  11. MySQL学习记录 (三) ----- SQL数据定义语句(DDL)
  12. Halcon:基本例程
  13. 条件随机场(CRF)小结
  14. 私塾在线《深入浅出学 Hadoop- 初级 部分》
  15. 自动控制原理 (二): 控制系统的微分方程
  16. ROS激光SLAM导航理解
  17. 新版edge浏览器换主题皮肤,使用Chrome浏览器的主题皮肤
  18. cs1.6一直连接服务器,CS1.6连接不上服务器解决办法
  19. 头孢是什么?什么是双硫仑反应?//2021-2-11
  20. Anycloud平台LOGO生成方法

热门文章

  1. Asp.net mvc 实时生成缩率图到硬盘
  2. .读取excel表格(JAVA)
  3. 低学历者为何能骗取30万年薪职位
  4. nls_lang.sh: 114: [[: not found
  5. Qt学习之路(11): MainWindow
  6. 安装云端服务器操作系统,安装云端服务器操作系统
  7. 格雷码 matlab,基于格雷码的结构光重建代码(MATLAB版本)
  8. 离散数学图论旅行规划问题_2020年MathorCup高校数学建模挑战赛——C 题 仓内拣货优化问题...
  9. 列的数目比列的名字要多_你们要的甘特图来啦!还有具体做法哦!
  10. mfc中UpdateData的用法