Linux系统编程(六)高级IO

目录

1. 阻塞和非阻塞 IO

2. IO 多路转接(select、poll、epoll)

3. 存储映射 IO(mmap)

4. 文件锁(fcntl、lockf、flock)

5. 管道实例 - 池类算法


1. 阻塞和非阻塞 IO

  • 阻塞 IO:会等待操作的完成或期待事情的到来。会被信号打断(信号会打断阻塞中的系统调用),若被打断则错误码为 EINTR(假错)。操作的完成和期待事件的到来会通知阻塞的进程。
  • 非阻塞 IO:若操作未完成或期待的事情还没到来,则立即返回,不会等待。若未发生期待事件则返回错误码 EAGAIN(假错)。不会通知,但可以通过轮询查看状态。

有限状态机编程例子,中继引擎实现,实现不同 tty 设备之间的中继引擎,实现 tty 之间相互通信,但是是忙等(因为没有使用阻塞 IO,没有用到同步手段):

1-io/advio/nonblock/relayer

2. IO 多路转接(select、poll、epoll)

上述有限状态机例子是 I/O 密集型任务,可以使用 IO 多路转接。 

IO 多路转接:监视文件描述符的行为,当当前文件描述符发生了期待的行为的时候,才去执行后续的操作。可以监视多个文件描述符。

1. select() 可以用来监视多个文件描述符,包括可读、可写、异常文件描述符,移植性很好,比较古老,传参不稳定。以事件为单位来组织文件描述符。监视期间会阻塞,也会被信号打断(假错)。

#include <sys/select.h>

int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);

// 删除指定的fd
void FD_CLR(int fd, fd_set *set);
// 判断fd是否在集合中
int  FD_ISSET(int fd, fd_set *set);
// 将fd加入到集合中
void FD_SET(int fd, fd_set *set);
// 清空集合
void FD_ZERO(fd_set *set);

缺点

  • 监视内容和监视结果存放在同一处 readfds、writefds、exceptfds。 
  • 文件描述符有大小限制。

2. poll() 可以等待在文件描述上发生的特定事件,以文件描述符为单位来组织事件。把期待的事件 events 和已经发生的事件 revents 区分开来了,可以移植。

#include <poll.h>

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

struct pollfd {
    int   fd;         /* file descriptor */
    short events;     /* requested events */
    short revents;    /* returned events */
};

如果将 timeout 设置为 0 即为非阻塞,-1 表示为阻塞。跳过 pollfd 结构体中的 events 来指定特定的期待事件。

3. epoll(),linux 基于 poll 来做的一些优化版本,不可移植。

#include <sys/epoll.h>

// 打开一个epoll文件描述符
int epoll_create(int size);
int epoll_create1(int flags);

// 控制epoll文件描述符
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

// 等待epoll文件描述符上的事件
int epoll_wait(int epfd, struct epoll_event *events,
               int maxevents, int timeout);
int epoll_pwait(int epfd, struct epoll_event *events,
                int maxevents, int timeout,
                const sigset_t *sigmask);

3. 存储映射 IO(mmap)

可以使用 readv(2) 和 writev(2) 来将读写多个碎片 buffer。

#include <sys/uio.h>

ssize_t readv(int fd, const struct iovec *iov, int iovcnt);

ssize_t writev(int fd, const struct iovec *iov, int iovcnt);

存储映射 IO 可以将某一块内存,或者某一个文件的内容映射到当前进程空间中

1. mmap(2) 可以将文件或者设备映射到内存中,返回映射区域的起始地址。

#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags,
           int fd, off_t offset);
int munmap(void *addr, size_t length);

参数: 

  • addr: 指定映射的虚拟内存地址,若为 NULL 则由内核选择合适的虚拟内存地址;
  • length:映射的长度;
  • prot:映射内存的保护模式,可选值如下:

  PROT_EXEC:可以被执行;

  PROT_READ:可以被读取;

  PROT_WRITE:可以被写入;

  PROT_NONE:不可访问;

  • flags:指定映射的类型,可选值如下:

  MAP_FIXED:使用指定的起始虚拟内存地址进行映射;

  MAP_SHARED:与其他所有映射到这个文件的进程共享映射空间(可实现共享内存);

  MAP_PRIVATE:建立一个写时复制(copy-on-write)的私有映射空间;

  MAP_ANONYMOUS:匿名映射,可以替代 malloc,不依赖于任何文件,并且当前空间被  初始化为 0;

  .....

  • fd:进行映射的文件描述符;
  • offset:文件偏移量(从文件何处开始映射);

例子1,mmap.c,使用 mmap 打开文件,并且计算文件中 a 字符出现的次数:

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
  if (argc < 2)
  {
    fprintf(stderr, "Usage..\n");
    exit(1);
  }

  int fd;
  void *addr;
  char *p;
  struct stat statbuf;
  int anum = 0;
  if ((fd = open(argv[1], O_RDONLY)) < 0)
  {
    perror("open");
    exit(1);
  }

  if (fstat(fd, &statbuf) < 0)
  {
    perror("fstat");
    exit(1);
  }

  addr = mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  if (addr == MAP_FAILED)
  {
    perror("mmap()");
    exit(1);
  }

  p = (char *)addr;
  for (int i = 0; i < statbuf.st_size; i++)
  {
    if (*(p + i) == 'a')
    {
      anum++;
    }
  }
  munmap(addr, statbuf.st_size);

  printf("the number of a in the file is: %d\n", anum);
  exit(0);
}

mmap 还能实现共享内存,从而实现有亲缘关系的进程间的通信。比如父进程先 mmap,然后再 fork,这样子进程也能访问父进程 mmap 出来的空间(flags 为 MAP_SHARED 和 MAP_ANONYMOUS)。

例子,share_mem.c,使用 mmap 实现父子进程间的共享内存(子进程写入 hello,父进程打印):

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

#define MEMSIZE 1024

int main()
{
  int fd;
  pid_t pid;
  char *addr;
  addr = (char *)mmap(NULL, MEMSIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
  if (addr == MAP_FAILED)
  {
    perror("mmap");
    exit(1);
  }

  pid = fork();
  if (pid < 0)
  {
    perror("fork");
    exit(1);
  }

  if (pid == 0) // child
  {
    strcpy(addr, "Hello!");
    munmap(addr, MEMSIZE);
    exit(0);
  }
  else // parent
  {
    wait(NULL);
    puts(addr);
    munmap(addr, MEMSIZE);
    exit(0);
  }
}

4. 文件锁(fcntl、lockf、flock)

对文件加锁是在 inode 结构体上进行的,如果对一个文件描述符进行了 dup 或者重新 open 了新的文件描述符,对不同的文件描述符加锁和解锁都是作用于同一个 inode 的。 有如下几种文件加锁方法:

fcntl() 前面讲过。Linux系统编程(二)文件IO/系统调用IO-CSDN博客

lockf() 可以对文件进行加锁或者解锁,在 linux 上 lockf 就是 fcntl 的封装。

#include <unistd.h>

int lockf(int fd, int cmd, off_t len);

flock() 可以给打开的文件加上或移除咨询锁(advisory lock)。

#include <sys/file.h>

int flock(int fd, int operation);

5. 管道实例 - 池类算法

例子:4-parallel/thread/mypipe。

Linux系统编程(李慧琴): Linux系统编程(李慧琴)学习代码及笔记

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

1. C++ 编译期多态与运行期多态

C 编译期多态与运行期多态 今日的C不再是个单纯的“带类的C”语言&#xff0c;它已经发展成为一个多种次语言所组成的语言集合&#xff0c;其中泛型编程与基于它的STL是C发展中最为出彩的那部分。在面向对象C编程中&#xff0c;多态是OO三大特性之一&#xff0c;这种多态称为运…

澳大利亚昆士兰大学博士后—成瘾和青少年药物使用

澳大利亚昆士兰大学博士后—成瘾和青少年药物使用 昆士兰大学&#xff08;The University of Queensland&#xff09;&#xff0c;简称“昆大”“UQ”&#xff0c;该校始建于1909年&#xff0c;是一所位于澳大利亚昆士兰州的公立综合性大学。同时还是六所砂岩学府之一&#xff…

Linux ubuntu 写c语言Hello world

文章目录 创建hello.c 文件进入hello.c 文件使用vim 编辑器进行编辑下载gcc 编辑器调用gcc 进行编译hello.c 创建hello.c 文件 touch hello.c进入hello.c 文件 vi hello.c使用vim 编辑器进行编辑 下载gcc 编辑器 sudo apt update sudo apt install gcc第一个语句是更新&am…

7.2 支付模块 - 付费课程选课、支付

支付模块 - 付费课程选课、支付模型 文章目录 支付模块 - 付费课程选课、支付模型一、需求分析1.1 执行流程1.2 订单服务设计1.3 创建订单服务1.4 支付宝接口 说明1.5 支付宝下单执行流程 二、支付 准备2.1 Maven 坐标2.2 支付宝配置参数2.3 生成二维码2.3.1 Maven坐标2.3.2 工…

英伟达板子4----存储满了系统黑屏

记录一个bug&#xff0c;因为最近在做边缘端视频处理的内容&#xff0c;就把视频存储在边端设备&#xff0c;但是发现由于边缘端设备的存储太小了&#xff0c;导致把ubuntu端的存储&#xff08;只有28个Gib&#xff09;给吃满了。 然后搜了一篇博客说重启就能释放一些空间&…

任务调度新境界:探秘ScheduledExecutorService的异步魔力

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 任务调度新境界&#xff1a;探秘ScheduledExecutorService的异步魔力 前言ScheduledExecutorService的基本概念基本概念&#xff1a;为何它是 Java 中任务调度的首选工具&#xff1a;基本用法&#xf…

使用mapbox navigation搭建一个安卓导航 示例

一.代码示例地址&#xff1a; https://github.com/mapbox/mapbox-navigation-android-examples/tree/main 二. 具体步骤&#xff1a; git clone gitgithub.com:mapbox/mapbox-navigation-android-examples.git Go to app/src/main/res/values Look for mapbox_access_token.…

力扣每日一题 找出字符串的可整除数组 数论

Problem: 2575. 找出字符串的可整除数组 文章目录 思路复杂度Code 思路 &#x1f468;‍&#x1f3eb; 灵神题解 复杂度 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( 1 ) O(1) O(1) Code class Solution {public int[] divisibilityArray(String word, int m){in…

多层菜单的实现方案(含HierarchicalDataTemplate使用)

1、递归 下面是Winform的递归添加菜单栏数据&#xff0c;数据设置好父子id方便递归使用 在TreeView的控件窗口加载时&#xff0c;调用递归加载菜单 private void LoadTvMenu(){this.nodeList objService.GetAllMenu(); // 通过Service得到全部数据// 创建一个根节点this.t…

Salesforce 2024财年爆发式增长!第一次现金分红

对于Salesforce来说&#xff0c;这是非凡的转型之年&#xff0c;所有的关键指标都表现强劲&#xff0c;现金流和利润增长创下了纪录。截至第四季度末&#xff0c;Salesforce的剩余履约价值&#xff08;RPO&#xff09;总额为569亿美元&#xff0c;同比增长17%。 Marc Benioff …

Unity引擎关于APP后台下载支持的实现问题

1&#xff09;Unity引擎关于APP后台下载支持的实现问题 2&#xff09;Prefab对DLL中脚本的引用丢失 3&#xff09;Unity DOTS资源加载问题 4&#xff09;UnitySendMessage和_MultiplyMatrixArrayWithBase4x4_NEON调用导致崩溃 这是第376篇UWA技术知识分享的推送&#xff0c;精选…

一文彻底搞懂从输入URL到显示页面的全过程

简略版&#xff1a; 用户输入URL后&#xff0c;浏览器经过URL解析、DNS解析、建立TCP连接、发起HTTP请求、服务器处理请求、接收响应并渲染页面、关闭TCP连接等步骤&#xff0c;最终将页面显示给用户。 详细版&#xff1a; URL解析&#xff1a;浏览器根据用户输入的URL&#x…

字符函数

1.字符分类函数 专门做字符分类的函数&#xff0c;都包含一个头文件#include <ctype.h> islower() 是一个用于判断字符是否为小写字母的函数。 通常情况下&#xff0c;如果一个字符是小写字母&#xff0c;则 islower() 函数会返回 true 或者一个表示真的值&#xff08…

STM32标准库——(19)PWR电源控制

1.PWR简介 PWR属于外设部分 调用时需要先开启时钟 2.电源框图 这个图可以分为三个部分&#xff0c;最上面是模拟部分供电叫做VDDA&#xff0c;中间是数字部分供电&#xff0c;包括两块区域&#xff0c;VDD供电区域和1.8v供电区域&#xff0c;下面是后备供电&#xff0c;叫做VB…

VM 虚拟机 ubuntu 解决无法连接网络问题

添加网卡法 就是在虚拟机的设置那里多增加一个网卡

python小白考教资(教资中的简单编程)

首先&#xff0c;写习惯了c语句的我&#xff08;虽然也会一丢丢&#xff09;&#xff0c;当然得深知python与C语言的一些简单的语句区别&#xff0c;这里为什么我要学习python呢&#xff0c;因为有些题目&#xff0c;python一句话就可以解决&#xff0c;但是以我的水平&#xf…

数据结构:AVL树

目录 1、AVL树的概念 2、二叉搜索树的功能与实现 1、AVL树节点定义 2、AVL树的插入 3、AVL树的旋转操作 1、左旋 2、右旋 3、左右旋 4、右左旋 3、AVL树完整代码实现 1、AVL树的概念 在前面的文章中&#xff0c;我们学过了二叉搜索树&#xff0c;二叉搜索树虽可以缩短查…

论文阅读_解释大模型_语言模型表示空间和时间

英文名称: LANGUAGE MODELS REPRESENT SPACE AND TIME 中文名称: 语言模型表示空间和时间 链接: https://www.science.org/doi/full/10.1126/science.357.6358.1344 https://arxiv.org/abs/2310.02207 作者: Wes Gurnee & Max Tegmark 机构: 麻省理工学院 日期: 2023-10-03…

142.乐理基础-音程的构唱练习

内容参考于&#xff1a;三分钟音乐社 上一个内容&#xff1a;141.乐理基础-男声女声音域、模唱、记谱与实际音高等若干问题说明-CSDN博客 本次内容最好去看视频&#xff1a; https://apphq3npvwg1926.h5.xiaoeknow.com/p/course/column/p_5fdc7b16e4b0231ba88d94f4?l_progra…

Python变量类型常用的函数【函数】

一、Python Number(数字)常用的函数 主要有math模块和cmath模块。 math模块&#xff1a;提供了许多对浮点数的数学运算函数。 cmath模块&#xff1a;提供了一些用于复数运算的函数。 使用两个模块里的函数时要先导入&#xff1a; import math查看math模块里的函数&#xff1a…