I/O进程5

  • day5
    • 十二、线程同步

      • 1.互斥
        • 1.1概念

          • 临界资源:一次仅允许一个进程所使用的资源
          • 临界区:指的是一个访问共享资源的程序片段
          • 互斥:多个线程在访问临界资源时,同一时间只能一个线程访问
          • 互斥锁:通过互斥锁可以实现互斥机制,主要用来保护临界资源,每个临界资源都由一个互斥锁来保护,线程必须先获得互斥锁才能访问临界资源,访问完资源后释放该锁。如果无法获得锁,线程会阻塞直到获得锁为止。
        • 1.2函数

          • int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
          • 功能:初始化互斥锁
          • 参数:
          • mutex:互斥锁
          • attr: 互斥锁属性 // NULL表示缺省属性
          • 返回值:成功 0 失败 -1
          • int pthread_mutex_lock(pthread_mutex_t *mutex)
          • 功能:申请互斥锁
          • 参数:mutex:互斥锁
          • 返回值:成功 0 失败 -1
          • 注:和pthread_mutex_trylock区别:pthread_mutex_lock是阻塞的;pthread_mutex_trylock不阻塞,如果申请不到锁会立刻返回
          • int pthread_mutex_unlock(pthread_mutex_t *mutex)
          • 功能:释放互斥锁
          • 参数:mutex:互斥锁
          • 返回值:成功 0 失败 -1
          • int pthread_mutex_destroy(pthread_mutex_t *mutex)
          • 功能:销毁互斥锁
          • 参数:mutex:互斥锁
        • 1.3练习

          • int a[10]={0,1,2,3,4,5,6,7,8,9}; 两个线程:一个线程打印,一个线程倒置
        • 1.4死锁

          • 1.4.1概念
            • 是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。
          • 1.4.2死锁产生的四个必要条件
            • (1)、互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
            • (2)、不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
            • (3)、请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
            • (4)、循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。 注意:当上述四个条件都成立的时候,便形成死锁。当然,死锁的情况下如果打破上述任何一个条件,便可让死锁消失。
      • 2.条件变量
        • 2.1步骤
          • pthread_cond_init:初始化
          • pthread_cond_wait:阻塞等待条件产生,没有条件产生时阻塞,同时解锁,当条件产生时结束阻塞,再次上锁。
          • pthread_mutex_lock(); //上锁
          • pthread_cond_wait(cond, lock); //如果没有条件产生时,解锁,当等待到条件产生时,上锁。
          • pthread_cond_signal:产生条件,不阻塞
          • pthread_cond_wait先执行,pthread_cond_signal再产生条件
        • 2.2函数接口
          • int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
          • 功能:初始化条件变量
          • 参数:
          • cond:是一个指向结构pthread_cond_t的指针
          • restrict attr:是一个指向结构pthread_condattr_t的指针,一般设为NULL
          • 返回值:成功:0 失败:非0
          • int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
          • 功能:等待信号的产生
          • 参数:
          • restrict cond:要等待的条件
          • restrict mutex:对应的锁
          • 返回值:成功:0,失败:不为0 注:当没有条件产生时函数会阻塞,同时会将锁解开;如果等待到条件产生,函数会结束阻塞同时进行上锁。
          • int pthread_cond_signal(pthread_cond_t *cond);
          • 功能:给条件变量发送信号
          • 参数:cond:条件变量值
          • 返回值:成功:0,失败:非0
          • 注:必须等待pthread_cond_wait函数先执行,再产生条件才可以
          • int pthread_cond_destroy(pthread_cond_t *cond);
          • 功能:将条件变量销毁
          • 参数:cond:条件变量值
          • 返回值:成功:0, 失败:非0
    • 十三、linux IO模型

      • 1.阻塞式IO:是常见,效率低,不浪费CPU

      • 2.非阻塞式IO:轮询、耗费CPU、可以处理多路IO

        • 2.1通过函数自带参数进行设置

        • 2.2.通过设置文件描述符属性设置非阻塞

          • int fcntl(int fd, int cmd, ... /* arg */ );
          • 功能:设置文件描述符属性
          • 参数:
          • fd:文件描述符
          • cmd:设置方式 - 功能选择
          • F_GETFL 获取文件描述符的状态信息 第三个参数化忽略
          • F_SETFL 设置文件描述符的状态信息 通过第三个参数设置
          • O_NONBLOCK 非阻塞
          • O_ASYNC 异步
          • O_SYNC 同步
          • arg:设置的值 in
          • 返回值:
          • 特殊选择返回特殊值 - F_GETFL 返回的状态值(int)
          • 其他:成功0 失败-1,更新errno
          • 使用:
          • 0为例
          • 0-原本:阻塞、读权限 修改或添加非阻塞
          • int flags=fcntl(0,F_GETFL);//1.获取文件描述符原有的属性信息
          • flags = flags | O_NONBLOCK;//2.修改添加权限
          • fcntl(0,F_SETFL,flags); //3.将修改好的权限设置回去
      • 3.信号驱动IO:异步通知方式,底层驱动的支持

        • 异步通知:异步通知是一种非阻塞的通知机制,发送方发送通知后不需要等待接收方的响应或确认。通知发送后,发送方可以继续执行其他操作,而无需等待接收方处理通知。

          • (1). 通过信号方式,当内核检测到设备数据后,会主动给应用发送信号SIGIO。
          • (2). 应用程序收到信号后做异步处理即可。
          • (3).应用程序需要把自己的进程号告诉内核,并打开异步通知机制。
            • //1.设置将文件描述符和进程号提交给内核驱动 //一旦fd有事件响应, 则内核驱动会给进程号发送一个SIGIO的信号 fcntl(fd,F_SETOWN,getpid());
            • //2.设置异步通知 int flags; flags = fcntl(fd, F_GETFL); //获取原属性 flags |= O_ASYNC; //给flags设置异步 O_ASUNC 通知 fcntl(fd, F_SETFL, flags); //修改的属性设置进去,此时fd属于异步
            • //3.signal捕捉SIGIO信号 --- SIGIO:内核通知会进程有新的IO信号可用 //一旦内核给进程发送sigio信号,则执行handler signal(SIGIO,handler);
      • 4.IO多路复用:select poll epoll

        • 4.1

          • ●应用程序中同时处理多路输入输出流,若采用阻塞模式,得不到预期的目的;
          • ● 若采用非阻塞模式,对多个输入进行轮询,但又太浪费CPU时间;
          • ● 若设置多个进程/线程,分别处理一条数据通路,将新产生进程/线程间的同步与通信问题,使程序变得更加复杂;
          • ● 比较好的方法是使用I/O多路复用技术。其基本思想是: ○ 先构造一张有关描述符的表(最大1024),然后调用一个函数。 ○ 当这些文件描述符中的一个或多个已准备好进行I/O时函数才返回。 ○ 函数返回时告诉进程那个描述符已就绪,可以进行I/O操作。
        • 4.2select

          • 4.2.1特点

            • (1).一个进程最多只能监听1024个文件描述符
            • (2).select被唤醒之后要重新轮询,效率相对低
            • (3).select每次都会清空未发生响应的文件描述符,每次拷贝都需要从用户空间到内核空间,效率低,开销大
          • 4.2.2编程步骤

            • (1).先构造一张关于文件描述符的表
            • (2).清空表 FD_ZERO
            • (3).将关心的文件描述符添加到表中 FD_SET
            • (4).调用select函数
            • (5).判断式哪一个或者式哪些文件描述符产生了事件 FD_ISSET
            • (6).做对应的逻辑处理
          • 4.2.3函数接口

            • int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
            • 功能: 实现IO的多路复用
            • 参数: nfds:关注的最大的文件描述符+1 readfds:关注的读表 writefds:关注的写表 exceptfds:关注的异常表 timeout:超时的设置 NULL:一直阻塞,直到有文件描述符就绪或出错 时间值为0:仅仅检测文件描述符集的状态,然后立即返回 时间值不为0:在指定时间内,如果没有事件发生,则超时返回0,并清空设置的时间值 struct timeval { long tv_sec; /* 秒 */ long tv_usec; /* 微秒 = 10^-6秒 */ };
            • 返回值: 准备好的文件描述符的个数 -1 :失败: 0:超时检测时间到并且没有文件描述符准备好
            • 注意: select返回后,关注列表中只存在准备好的文件描述符
            • 操作表: void FD_CLR(int fd, fd_set *set); //清除集合中的fd位 void FD_SET(int fd, fd_set *set);//将fd放入关注列表中 int FD_ISSET(int fd, fd_set *set);//判断fd是否在集合中 是--》1 不是---》0 void FD_ZERO(fd_set *set);//清空关注列表
          • 4.2.4练习

            • 输入鼠标的时候,响应鼠标事件,输入键盘的时候,响应键盘事件 (两路IO)
          • 4.2.5超时检测

            • (1).概念
              • 什么是网络超时检测呢,比如某些设备的规定,发送请求数据后,如果多长时间后没有收到来自设备的回复,那么需要做出一些特殊的处理
              • 比如: 链接wifi的时候,等了好长时间也没有连接上,此时系统会发送一个消息: 网络连接失败
            • (2).必要性
              • (1). 避免进程在没有数据时无限制的阻塞;
              • (2).规定时间未完成语句应有的功能,则会执行相关功能
        • 4.3poll

          • 特点
            • (1).优化文件描述符的限制,文件描述符的限制取决于系统
            • (2).poll被唤醒之后要重新轮询一遍,效率相对低
            • (3).poll不需要重新构造表,采用结构体数组,每次都需要从用户空间拷贝到内核空间
        • 4.4epoll:百万级

          • 特点
            • (1).监听的最大的文件描述符没有个数限制
            • (2).异步IO,epoll当有事件产生被唤醒之后,文件描述符主动调用callback函数(回调函数)直接拿到唤醒的文件描述符,不需要轮询,效率高
            • (3).epoll不需要重新构造文件描述符表,只需要从用户空间拷贝到内核空间一次。
        • 4.5总结

相关推荐
序属秋秋秋几秒前
算法基础_数据结构【单链表 + 双链表 + 栈 + 队列 + 单调栈 + 单调队列】
c语言·数据结构·c++·算法
独行soc6 分钟前
2025年常见渗透测试面试题-红队面试宝典下(题目+回答)
linux·运维·服务器·前端·面试·职场和发展·csrf
Pitayafruit12 分钟前
SpringBoot整合Flowable【08】- 前后端如何交互
spring boot·后端·workflow
王鑫的博客88632 分钟前
本地git操作
c语言·git
小丁爱养花37 分钟前
驾驭 Linux 云: JavaWeb 项目安全部署
java·linux·运维·服务器·spring boot·后端·spring
apcipot_rain1 小时前
【密码学——基础理论与应用】李子臣编著 第五章 序列密码 课后习题
算法·密码学
不要不开心了1 小时前
sparkcore编程算子
pytorch·分布式·算法·pygame
88号技师1 小时前
【2024年最新IEEE Trans】模糊斜率熵Fuzzy Slope entropy及5种多尺度,应用于状态识别、故障诊断!
人工智能·算法·matlab·时序分析·故障诊断·信息熵·特征提取
uhakadotcom1 小时前
Amazon GameLift 入门指南:六大核心组件详解与实用示例
后端·面试·github