
Linux
文章平均质量分 83
Linux学习记录
栖林_
一个励志于做全栈工程师的平平无奇大学生,希望在这里留下自己学习的记录
展开
-
Linux文件描述符详解及其应用
系统会为进程分配一张文件描述符表(FD Table),其中每个打开的文件或资源都会占用一个文件描述符,进程通过文件描述符来读写、控制和管理这些资源。在编程中,可以通过重定向这些文件描述符来改变数据的输入和输出位置,例如将标准输出重定向到文件,或从文件而不是键盘读取输入。每当打开一个文件时,系统会返回一个文件描述符,后续对文件的所有操作(如读取、写入、关闭)都依赖这个文件描述符。每个进程在打开文件、套接字等资源时,操作系统会分配一个可用的文件描述符。文件描述符使文件的操作变得简单,能统一处理不同的资源。原创 2024-10-26 14:08:49 · 1667 阅读 · 0 评论 -
Linux下的线程同步与死锁避免
即,线程只有在能够获取所有资源时才会继续执行,否则会释放已经持有的资源,避免持有并等待的发生。为了避免这种情况,我们可以在申请资源之前,确保线程不占有其他资源,或者一次性申请所有所需资源。在某些情况下,我们可以通过将资源转换为可共享的资源来破坏互斥条件,从而避免死锁。是指存在一个线程循环等待链,每个线程都在等待下一个线程持有的资源。通过一次性申请资源,线程要么成功获取所有资源并继续执行,要么立即释放资源,减少持有并等待的风险。通过这种方式,线程不会无限期地等待资源,从而避免了死锁的发生。原创 2024-10-26 14:07:51 · 1209 阅读 · 0 评论 -
Linux环境C++多线程调试工具和内存泄漏工具介绍
幸运的是,Linux 提供了多种调试工具来帮助我们排查多线程相关的问题和内存泄漏。AddressSanitizer 是 GCC 和 Clang 编译器中的另一个强大的工具,用于检测内存错误,包括越界访问、堆栈溢出和内存泄漏。除了多线程问题,内存管理也是 C++ 程序中常见的挑战之一。执行该命令后,Valgrind 会跟踪程序的所有内存分配和释放情况,并在程序结束时给出详细的报告,指出泄漏的内存位置和大小。是一个用于跟踪程序执行时系统调用的工具,对于多线程程序,它可以帮助开发者检查线程相关的系统调用(例如。原创 2024-10-26 14:07:03 · 1166 阅读 · 0 评论 -
Linux中exec系列函数与fork函数
函数是进程管理中的两个重要组成部分。它们在创建和执行进程时扮演着关键角色,理解它们的工作原理及相互关系对于系统编程至关重要。后,当前进程(父进程)会被复制一份,生成一个新的进程(子进程)。一起使用,以便创建新的进程并在其中执行新程序。系列函数用于在当前进程的上下文中执行新的程序。在 Linux 和其他 Unix-like 操作系统中,后,当前进程的代码和数据将被新程序替换。是用于创建新进程的系统调用。原创 2024-10-21 12:33:23 · 722 阅读 · 0 评论 -
SQLite数据库介绍
SQLite是一个本地化的数据库,不需要客户端服务端什么的配置,主打就是轻量化方便化。他也不是一个独立的进程,而是可以根据应用程序的需求,可以进行静态或者动态的连接。第三个参数是flag是可以设置文件的打开方式,提供下面的宏可以选择。需要注意的是 在SQLite中一个数据库对应了一个数据库文件。而且他是直接存储在磁盘文件的,提供了简单易用的API接口。第一个参数是文件名,第二个参数是传入一个句柄指针的地址。如果是其他值的话就代表着有问题,需要查找对应的宏来看到。这是一个执行语句的操作函数。原创 2024-09-30 19:32:06 · 911 阅读 · 0 评论 -
Linux高级IO之poll与epoll
epoll的默认工作模式就是水平触发,当epoll检测到事件就绪时,可以不立即进行处理,或者仅处理一部分,一直到缓冲区的所有数据都被处理完,才不会立即返回,支持阻塞和非阻塞。poll和epoll都是多路转接的调用,但是epoll实在过于优秀了,一般也都是用epoll的,除此之外还着使用时还蕴含着Reactor设计模式的思想。边缘触发就是类似于非阻塞的情况,事件发生时,只通知一次,爱拿不拿,不保证数据依然还在,你只有一次处理机会。events表示事件发生时要做的操作,也就是需要监听的事件。原创 2024-09-27 19:36:56 · 1035 阅读 · 0 评论 -
Linux高阶IO之select多路转接
select能够同时监视多个文件描述符,但是也总是有上限的,上限就是fd_set位图的大小除此之外,我们不仅需要维护fd_set,还需要额外维护放入fd_set中的数据集,否则我们无法使用FD_ISSET判断文件描述符是否就绪而且每一次都需要重新逐一加入fd_set,然后再取出最大的文件描述符,作为第一个参数输入所以这个系统调用是真难用,非常不便,还需要将fd_set从用户态拷贝到内核态,fd_set也不够大但是这是第一个,有缺陷才是正常的,后面才会越来越好,有了poll和epoll。原创 2024-09-26 16:41:11 · 354 阅读 · 0 评论 -
Linux高级IO之五种IO模型
而交换则对应了输入和输出两个部分,由于计算机网络的影响,IO也不应当狭义的理解为从内存中IO,而应当也扩展至从网络中IO,虽然设备上,是内存和网卡的区别,但是对于Linux来说他们都是文件,是没什么区别的。在IO时,一共做了两件事情,第一件事情是等待,等待缓冲区的文件,或是网卡上来,或是从内存中来,第二件事情是拷贝,将缓冲区数据拷贝到内存中。类似于计算机发展的过程,计算机开始时是等待IO和处理数据两个过程,然后逐步演化为现在的并发情景,将等待IO的时间减少,处理数据的时间增加。原创 2024-09-26 12:16:01 · 912 阅读 · 0 评论 -
Linux网络之UDP与TCP协议详解
这段时间服务器什么也没有等到,服务器说,这是我跟你说的最后一句话,以后再也没有了(假),拜拜(发送了一个LAST_ACK,表示最后一个ACK报文,并且附带了FIN标志,表示结束)如果服务器发送了1到20号数据,但是客户端收到的是1和3到20,只发了一个2的请求,服务器看到之后觉得他只收到了1,于是把2到20又发了一遍,这样的效率又变得不行了。这里需要知道一点,当我发出一条消息的时候,我是不知道这条消息能不能传达到的,但是可以确定的是,我之前的消息一定传到了,并且我也可以收到对方的消息。原创 2024-09-23 20:38:24 · 1144 阅读 · 0 评论 -
Linux网络——HTTPS详解
这样做,即便是服务器自身想要修改公钥都是不行的,只能向CA机构申请,因为数字签名是由CA私钥生成的,一旦篡改就会被认为不安全。跟随着证书一起发去,当对方收到这些之后,用公钥对数据签名进行解密,然后和证书进行比对,一旦出现差错,就说明证书有问题。流程是这样的,当客户端和服务器第一次交流时,客户端获取到服务器中生成的公钥S,而服务器自身有私钥S’如果说是要掉包证书,不能只改公钥,因为哈希值不一样,他没有服务器的私钥,算不出来正确的哈希值。这样就能确认公钥一定是服务器的而非中间人的了,后面的对称也都是安全的了。原创 2024-09-23 08:35:01 · 1246 阅读 · 0 评论 -
Linux网络——HTTP协议详解(2)
3开头的重定向操作还是蛮有用的,就类似于手机的呼叫转移,当某一个网站(服务器)暂时无法访问时,可以转接到另一个网站或者服务器,在某些情况下,这种转接甚至是永久的(301)浏览器能记住,也就是cookie,他可以存在内存里,也可以存在一个单独的cookie文件,当账号密码直接以明文的形式存在里面的时候,其实还是不安全。我们需要记住的其实就是大概知道是哪里出问题了,2开头的基本上没问题,3开头是可以重定向操作,4开头就是请求错了,5开头是服务器错误。原创 2024-09-22 17:48:16 · 335 阅读 · 0 评论 -
ProtoBuf序列化框架介绍
ProtoBuf全称是Protocol Buffer,是一个数据结构的序列化和反序列化框架他又很多好处,首先是他支持跨平台,支持Java、C++、Python等多种语言,还比XML更小更快更简单除此之外还可以更新数据结构,不会破坏原有的结构。原创 2024-09-21 21:39:04 · 501 阅读 · 0 评论 -
Linux网络——HTTP协议详解(1)
第一行就是请求行,主要有三个内容,第一个是请求方法,这里我们看到是GET,其实还有别的方法,第二个是url,第三个是版本,有1.0短连接,1.1长连接和2.0。HTTP可以说是当今应用最广泛的应用层协议之一,主要面向的是浏览器(客户端)和服务器之间通信的规定。HTTP协议的底层是TCP协议,我们先大概认识一下这个协议是如何使用的。虽然看起来很乱,但是可以分为三个部分,请求行,报头,空行,正文。这里我们写了一个简单的程序,获得了请求的报文,是长这个样子的。,但这个其实是省略过后的,完整的长这样。原创 2024-09-18 18:31:40 · 467 阅读 · 0 评论 -
Linux网络——手撕TCP服务器,制定应用层协议,实现网络版计算器
我们想发送的数据不一定是单纯的数值、字符,完全有可能是结构体,是类,我们想要传输这些内容,需要做的就是讲这些数据和结构体转换为字节流,这个过程我们称之为序列化。除此之外,既然是面向字节流的,我们如何知道一段数据的开始和结尾呢,就像水流一样,如果不做限制是很难分清的,因此我们还需要在数据的开始和结尾做标识。而且这个序列化和反序列化的过程是必须要相同的规则,不然就像字符串加密解密一样,没办法得到你想要的数据,这个相同的规则规矩,我们就称之为协议。那么反过来,从字节流解释出来各种数据和结构体的过程就是反序列化。原创 2024-09-17 14:07:07 · 826 阅读 · 0 评论 -
Linux网络——守护进程、会话、进程组
会话是session,代表的是客户端与服务器的一次交互过程,我们可以简单理解为,当我们打开一个终端,在用户登录时,就是创建了一个会话。当Linux系统启动时,或者bash启动时,会启动很多进程服务,例如ssh连接,或者一些代理服务,在进程终止或者系统终止时服务才停止。守护进程也叫做精灵进程,Deamon,是一种运行在后台的进程,所谓前台后台可以简单理解为能否直接收到键盘指令的进程。一个会话中可能有很多进程,我们称之为进程组,为了表示也就有了进程组ID:PGID,会话ID:SIG。原创 2024-09-15 23:58:46 · 528 阅读 · 0 评论 -
Linux网络——socket编程与UDP实现服务器与客户机通信
在同一台计算机的进程是通过进程id区分的,而要在对方的计算机中按照进程id来找恐怕不是一共好的想法,因为你也不知道对方进程的id是多少,于是就商量(传输层协议)使用port端口来确定进程。除此之外,TCP由于建立了连接,就可以像水流一样传输数据,是面向字节流的,而UDP则没有,所以UDP是面向数据包的。TCP面向的是有连接,意思是在正式的传递信息之前,需要建立连接,确保是能收到的,就像对暗号一样,土豆土豆我是地瓜。这里就是客户机的主体了,里面的代码和注释写的非常详细,主要思路就是初始化,先听,后回复。原创 2024-09-11 18:53:14 · 2045 阅读 · 0 评论 -
Linux网络——从《计算机网络》到网络编程
计算机网络也是如此,OSI标准将从下向上设计了七层网络模型,他设计的非常非常好,但是在实践中四层模型就能很好的解决问题,也称之为TCP/IP四层模型,在我们学习的过程中将物理层和数据链路层分开,变成五层模型。当应用层的两个进程想要通信时,实际上的数据是自己的电脑从应用层到传输层到网络层到链路层,层层套上自己的包头,让别人认识自己,让对方认识自己。除此之外,我们在组织数据,处理任务的时候,从来都是将大问题化成小问题,解决了小问题再将各个模块拼起来,就成了如今庞大的知识体系。原创 2024-09-10 21:56:14 · 1540 阅读 · 0 评论 -
Linux多线程——日志任务的线程池实现
我们将之前的所有内容可以串联起来做一个小型项目,非常建议阅读并自行实现,写代码才是学习编程的最好方式。定义一个ThreadData,用于获取当前线程的信息,可以添加别的信息,例如创建时间,运行时间等。主要运用的场景是需要大量现场完成任务,任务完成时间较短,例如WEB服务器中的网页请求。这里主要完善了日志系统写的方式,可以向屏幕输出、单个文件输出、按照等级划分的文件输出。线程池可以说是把之前所有的内容全部串联起来的一个项目。就是创建固定数量的线程,然后往任务列表里推送任务即可。线程池的使用非常简单。原创 2024-09-08 13:13:42 · 568 阅读 · 0 评论 -
Linux多线程——POSIX信号量与环形队列版本之生产消费模型
上一篇文章的生产消费模型是基于阻塞队列的,而且只用了互斥同步锁的内容,我们感觉效率其实不高,因为需要频繁考虑互斥同步问题。第一个是声明的信号量,第二个是选项,0表示线程间共享,非0表示进程间共享,第三个表示信号量的初始值。除此之外,还需要互斥锁,因为消费者之间和生产者之间也需要互斥访问。在生产者与消费者模型里面,生产者与消费者所认为的资源是不同的。消费者认为数据是资源,因为每次都会拿东西,数据会变少。但是实现的功能是一样的,都是为了解决同步的问题。我们说信号量指的就是资源的数量。发布信号量就是V操作。原创 2024-09-07 16:00:12 · 437 阅读 · 0 评论 -
Linux多线程——互斥锁的封装与生产消费模型的实现
为了更方便的使用互斥锁,我们把系统提供的互斥锁接口进行封装,并且贯彻一下RAII思想,让我们的使用更加方便。生产者与消费者之间的关系,不允许一边写一边取,这是互斥关系,并且要求先写后取,这是互斥关系。我们这样定义,生产者负责布置任务,然后通过阻塞队列,传递给消费者,让消费者完成任务。生产者与生产者之间的关系,我们不允许两个生产者共同写,他们之间是互斥关系。消费者与消费者的关系,我们也不允许两个消费者共同取,他们之间也是互斥关系。这里的产品可以是很多东西,我们可以认为产品是一个类,这个类可以是一切。原创 2024-09-06 19:51:43 · 333 阅读 · 0 评论 -
Linux多线程——线程互斥与同步和其他概念
重入指的是,同一个函数被不同的执行流调用时,当一个执行流还没有执行完成,另一个执行流就再次进入的情况。一般来说,函数可重入,那么线程一定是安全的,如果函数不可重入,那么就不允许多线程并发使用。第一个是要初始化的互斥量,我们在调用之前声明一共传入即可,第二个我们传入NULL。进程资源等待的前提是,拿到锁进入临界区,所以wait函数需要条件变量和互斥锁。当互斥量已经被上锁了,这个线程就会被阻塞,等待互斥量解锁。竞态条件指的是,因为时序问题,导致的程序问题。当原来的互斥量没有被加锁,此时加锁就会成功。原创 2024-09-04 17:27:42 · 1048 阅读 · 0 评论 -
Linux多线程——利用C++模板对pthread线程库封装
因为这个类创建之后并没有真正创建线程,没有分配线程id,而Start作为主线程需要完成的任务就是创建新线程,更改线程的运行状态,返回线程创建成功与否。这样一来,作为静态成员函数是无法直接使用类内成员的,也就是无法使用这个回调函数,因此将this指针作为参数传递进去是一个很好的选择。我们使用C++的模板对其封装可以让他的使用更加方便,并且经过测试可以让我们更加直观的了解到线程互斥和同步的重要性。如果我们直观理解的话,其实就是在判断的时候,在五个线程都只剩下了1张票时,几乎同时进了这个判断。原创 2024-09-03 21:48:27 · 843 阅读 · 0 评论 -
Linux多线程——线程的概念和控制
一共有四个参数,第一个是线程ID,第二个是选项,目前只设置为空指针即可,第三个选项是需要让新线程走的执行流,第四个是传递给其中的参数。那么一个进程他的执行路线至少有一个,也就算做是一个线程,这个进程本身也可以创建分支线程,那么原来的这个进程也就叫做主线程。从操作系统课本里我们可能听说过,线程是一个微缩版的进程,他拥有TCB,不会被分配资源,是CPU进行调度的单位。每一种信号的处理方式都是共享的。在CPU的视角来看,他的所调度的所有单位都是PCB,是同一个进程,CPU也无法分辨他运行的是线程还是进程。原创 2024-08-28 16:46:03 · 1062 阅读 · 0 评论 -
Linux进程信号——信号的捕捉、保存、处理
最本质里面,其实就是在CPU中的CR3寄存器中,表示当前CPU处于什么状态,1表示内核态,3表示用户态,而这个寄存器对于用户也是不可见的,只由操作系统管理。这个位图用来存储收到的信号,0或1表示是否收到,某一个位置表示对应的信号,这个位图也称之为信号集,也就是未决的情况。这个数组是一个函数指针数组,里面的内容是函数指针,下标表示收到n号信号,调用的处理方法就是对应的函数指针。需要注意的是,在使用sigset_t之前,一定要调用前面的任意一个初始化函数,让整个信号集处于确定的状态。原创 2024-08-27 13:02:46 · 1156 阅读 · 0 评论 -
Linux进程间通信——互斥锁与信号量详解
当P2操作先执行时,进行P操作申请资源,此时P1进程没有释放资源,所以P2进程被阻塞,真正原因其实是因为func1没有被执行,因此所谓的“资源”没有被释放,P2阻塞,于是P1进程运行,只有当P1进程释放资源之后,P2进程才能继续运行func2。这实际上是一种预定操作,虽然现在没有资源,但是我预定好了,并且一直处于等待队列中吗,并且手动block阻塞,不会让其占用CPU,等待释放资源,轮到我了,我再进行唤醒,我自然就可以使用了。也就是先运行的进程,进行V操作释放操作,后运行的进程进行P操作申请操作。原创 2024-08-27 11:05:38 · 1446 阅读 · 0 评论 -
Linux进程信号——信号的概念与产生
信号本身其实就是一种通知的形式,用户或者操作系统可以通过信号给进程发送信息,让进程来进行处理例如前台进程可以发送一个ctrl + c指令来中断进程我们可以使用kill -l查看进程信号表这些个信号存在文件中,大致可以分为两类,从1到31是标准信号,其余的都是POSIX实时信号,都有不同的含义ctrl + c其实就对应着2号信号Value表示信号编号、Action表示默认行为Term表示终止、Core稍后会讲解。原创 2024-08-25 12:09:17 · 750 阅读 · 0 评论 -
Linux进程间通信——硬件实现临界区互斥的基本方法
当两个进程都不使用时,lock为false,执行到进入区时,另一个进程不允许再次进入执行,第一个进程检查并上锁后,第二个进程只能等待第一个进程执行完临界区代码。这一段是多进程代码,也就是有两个进程都有相同的这一段,lock是全局变量,true表示临界资源被占用,初始值为false。操作系统有一个系统级的指令是中断指令,主要分为两个步骤,一个是关中断指令,另一个是开中断指令。这是一条硬件指令,TS指令,这条指令是原子操作,也就是原语,不允许被中断。再次强调,这个硬件指令是由硬件指令实现的,并非代码。原创 2024-08-25 11:21:02 · 283 阅读 · 0 评论 -
Linux进程间通信——软件实现临界区互斥的基本方法
假如P0进程想访问临界区,就先查看P1进程是否想用(flag[1]是否为true),是的话就等待,不是的话就把自己的设为true,然后访问临界区,访问完之后把自己设为false。这就相当于先声明我要拉,后一步检查对方要不要,但是我们继续考虑并发的情况,如果两个进程几乎同时声明自己要拉,检查的时候两个进程都会一直循环等待,结果就导致谁都没办法拉了。这就相当于一个人在拉之前先问一句,你要不要拉,你要拉的话那你先,你不拉那我要拉了,拉完之后跟他说拉完了,你可以去了。原创 2024-08-21 13:21:54 · 648 阅读 · 0 评论 -
Linux进程间通信——SystemV消息队列与信号量
我们就可以让A进程先使用P操作将资源占据,B进程再使用P操作的时候,发现资源没有了,只能阻塞,直到A进程执行了V操作释放资源,B进程才得以继续运行。互斥在我们生活中也有遇到过,例如手机摄像头,当你打微信视频的时候,就没办法用相机拍照,当一个人用打印机的时候,另一个人就没办法控制。这种资源称之为临界资源,那么共享内存其实就不算临界资源,除非我们也做保护,访问临界资源的代码也称为临界区。当操作取出的接口时,给第一个进程另一个进程的数据块,给第二个进程第一个进程的数据块。原创 2024-08-20 19:03:26 · 1020 阅读 · 0 评论 -
Linux进程间通信——SystemV共享内存
at是attach是关联的意思,因为共享的物理内存是属于操作系统的,我们需要将共享的内存挂载到进程地址空间的共享区,就要用到shamat。对于第一个参数,key是需要确定唯一的,类似于手机号,你自己有,别人不能再有一模一样的,并且别人想要打给你也必须输入一模一样的。shmid是共享内存id,cmd表示操作,buf是用来获取共享内存的属性的,各种属性都存在该结构体里。需要注意的是,共享内存在进程退出时是不会主动释放的,需要用户手动释放,除非系统内核关闭。第三种方法主要是为了确保所使用的共享一定是新鲜的。原创 2024-08-18 18:39:59 · 509 阅读 · 0 评论 -
Linux进程间通信——命名管道
之前我们使用的都是匿名管道,命名管道与之不同的就是他拥有实体文件,文件类型为p,而且他的文件大小永远为0。当两个进程分别打开管道时,如果分别分配两个缓冲区,连接着管道文件本体,这样实在低效。第一个参数是管道文件,第二个参数是权限,和open系统调用一样。命名管道也称之为fifo,先进先出,也可以理解其是单向的。他的返回值是int类型,返回值为-1时表示出创建管道失败。可以使用系统调用接口,也可以使用C语言接口都是没问题的。这时因为打开文件的同时也打开了缓冲区。创建管道文件完成之后的任务就简单了。原创 2024-08-17 17:34:55 · 246 阅读 · 0 评论 -
Linux进程间通信——池化技术与模拟实现进程池
这里其实还有一个隐藏起来的bug,就是在第二个子进程以及之后的子进程fork的时候,实际上他拷贝的是父进程的文件描述符表,因此他也存在一个接口指向之前申请的写接口,只有最后一个子进程是只有一个写接口的。蓝色是每一次我们fork子进程和pipe管道之后,需要关闭的接口,因为每一次的读接口都是3,所以从4、5、6以后的分别对应的就是不同的子进程的写管道。子进程的work是一直循环接收父进程传递的消息,若有效接收,则判断是否为任务列表中的任务,然后执行,若父进程写口关闭,则跳出读取循环,关闭子进程。原创 2024-08-16 16:19:07 · 767 阅读 · 0 评论 -
Linux进程间通信——匿名管道
然后再用fork函数创建子进程,由于子进程是写时拷贝父进程的,因此对子进程来说,他的文件描述符表也有一个读接口和一个写接口是指向匿名管道的。这个pipe函数实际上做了什么操作呢,可以简单理解为,操作系统创建了一个文件,然后再给两个文件标识符,一个用来表示读,一个用来表示写。因此进程间通信还是很必要的,除此之外网络通信中所说的进程间通信本质上也是两个进程进行通信,只不过信息传递经过了繁杂的计算机网络。再深入一点,管道的本质其实就是一个被打开的文件,但同时能被两个进程访问,而且只能一个进程写,另一个进程读。原创 2024-08-14 20:32:29 · 489 阅读 · 0 评论 -
Linux基础IO——文件系统与动静态库
我们之前所说的文件读写都是通过进程对已经打开的文件进行操作,也就是对操作系统对文件所创建的结构体进行操作那么对于磁盘中没有打开的文件是如何进行管理的。原创 2024-08-11 15:28:57 · 1129 阅读 · 0 评论 -
Linux基础IO——重定向与文件缓冲区
IO设备的读写速度是远低于内存和CPU的运转速度的,这其实就说明了缓冲区的重要性,不要让CPU和内存频繁访问IO设备,多和文件缓冲区打交道,当满足条件的时候,一起传递给外设即可。其实就是跟我们前一节内容所讲的一样,通过修改文件描述符表,修改文件描述符到指定文件的指针即可,也就是修改文件描述符下标为1的数组内容,改成到你想要的文件即可。我们就可以推断出,C语言提供的所有IO相关函数都与系统调用的接口对应,从本质上,所有访问文件的操作都是通过文件描述符fd来访问的。我们在学习Linux的基本内容时候,知道。原创 2024-08-07 19:38:12 · 369 阅读 · 0 评论 -
Linux基础IO——文件的系统调用与文件描述符的本质
C语言打开文件的函数是fopen,读取是fread、fscanf、fgets,写入是fwrite、fprintf、fputs,和基础的scanf、gets使用都是一致的,只需要在末尾加上写入的文件指针即可。可以从键盘读入,显示器输出,也可以输出到文件中,那么其实在操作系统内部,他是把显示器、键盘等外设也看作是文件,向显示器输出和向磁盘文件中输出写入是没有本质区别的。write是写入数据,写入的内容是buf,写入的字节数是count,调用成功就返回文件中的字节数。原创 2024-08-05 17:35:53 · 426 阅读 · 0 评论 -
Linux进程控制——进程程序替换、bash的模拟实现
其实在Linux环境下,程序替换不仅可以替换C语言程序,甚至可以替换成Python程序、Java程序去执行他们的内部代码,这就变相实现了不同语言之间的联动。我们之前介绍过内建命令,说这种命令只能让父进程调用,例如cd命令,因为写时拷贝,子进程进了某个文件夹,对父进程是没有影响的,也只有在父进程执行才有意义。这是里面最简单的函数,他的函数有两个,第一个是执行的程序路径,之后的是参数包,表示如何执行该程序。这里一共有六个函数,但是是同一个系列的,也有一定的规律,如果他们替换失败了,返回值都是-1。原创 2024-08-01 18:21:30 · 456 阅读 · 0 评论 -
Linux进程控制——进程等待
我们知道的是,当子进程创建出来之后,父进程是不会进入到判断语句中的,而且也没有打印等待子进程,而是一直在执行waitpid这一行,是一直等到子进程执行完毕之后才继续执行的。意思是 waiting no hang 父进程会继续运行下面的代码,因为waitpid的返回值是进程退出的pid,我们也就可以用这个来判断,子进程是否结束。option参数的默认值为0,表示阻塞等待,就是说父进程啥也不干,就等着子进程结束,那如果想让父进程可以在等待的时候做自己的事情,就需要用一个宏定义。父进程需要对子进程进行回收。原创 2024-07-28 17:56:11 · 429 阅读 · 0 评论 -
Linux进程控制——进程终止
一个进程中只有一个main函数,也有的书中将函数称之为子程序,这是因为函数也可以return值,那么其实就可以说明,非main函数return时,表示这个函数完毕,而main函数执行到return时,说明这个进程执行完毕。exit是c语言提供的库函数,_exit是由操作系统提供的系统调用,就说明了,缓冲区其实不是由操作系统来维护的,而是由实现他的c语言标准来维护的。异常终止的情况主要是由信号来控制的,此时我们再讨论程序的退出码其实就没有意义了,因为程序根本就没有正常执行下去,例如数组越界,原创 2024-07-27 18:07:24 · 523 阅读 · 0 评论 -
Linux进程——程序地址空间详解
我们刚刚已经知道了,程序显示给我们的地址并非真正的物理地址,其实是虚拟地址,也称为线性地址直接扯概念就太难受了,我们形象的来解释操作系统是内存资源的管理者,而每一个进程都想获取操作系统手上的内存资源但是操作系统又不好提前设定每个进程的内存大小,就只好告诉他们,我目前有32G(全部并有限)的内存,你可以来申请这里的32G就是全部的物理内存,但是有那么多进程,不可能每个都有32G,那明显不够分的,但是每个进程又以为自己有32G这就像老板给你画的饼,你好好努力就可以年薪百万,事实上并没有。原创 2024-07-26 21:17:13 · 391 阅读 · 0 评论