守护进程(Daemon Process),也就是通常说的 Daemon 进程(精灵进程),是 Linux 中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。一般采用以d结尾的名字。
1. 进程组多个进程的集合就是进程组, 这个组中必须有一个组长, 组长就是进程组中的第一个进程,组长以外的都是普通的成员,每个进程组都有一个唯一的组ID,进程组的ID和组长的PID是一样的。
进程组中的成员是可以转移的,如果当前进程组中的成员被转移到了其他的组,或者进制中的所有进程都退出了,那么这个进程组也就不存在了。如果进程组中组长死了, 但是当前进程组中有其他进程,这个进程组还是继续存在的。下面介绍几个常用的进程组函数:
得到当前进程所在的进程组的组ID
1pid_t getpgrp(void);
获取指定的进程所在的进程组的组ID,参数 pid 就是指定的进程
1pid_t getpgid(pid_t pid);
将某个进程移动到其他进程组中或者创建新的进程组
1int setpgid(pid_t pid, pid_t pg ...
共享内存不同于内存映射区,它不属于任何进程,并且不受进程生命周期的影响。通过调用Linux提供的系统函数就可得到这块共享内存。使用之前需要让进程和共享内存进行关联,得到共享内存的起始地址之后就可以直接进行读写操作了,进程也可以和这块共享内存解除关联, 解除关联之后就不能操作这块共享内存了。在所有进程间通信的方式中共享内存的效率是最高的。
共享内存操作默认不阻塞,如果多个进程同时读写共享内存,可能出现数据混乱,共享内存需要借助其他机制来保证进程间的数据同步,比如:信号量,共享内存内部没有提供这种机制。
1. 创建/打开共享内存1.1 shmget在使用共享内存之前必须要先做一些准备工作,如果共享内存不存在就需要先创建出来,如果已经存在了就需要先打开这块共享内存。不管是创建还是打开共享内存使用的函数是同一个,函数原型如下:
123#include <sys/ipc.h>#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);
参数:
key: 类型 key_t 是个整 ...
Linux
未读1. 创建内存映射区如果想要实现进程间通信,可以通过函数创建一块内存映射区,和管道不同的是管道对应的内存空间在内核中,而内存映射区对应的内存空间在进程的用户区(用于加载动态库的那个区域),也就是说进程间通信使用的内存映射区不是一块,而是在每个进程内部都有一块。
由于每个进程的地址空间是独立的,各个进程之间也不能直接访问对方的内存映射区,需要通信的进程需要将各自的内存映射区和同一个磁盘文件进行映射,这样进程之间就可以通过磁盘文件这个唯一的桥梁完成数据的交互了。
如上图所示:磁盘文件数据可以完全加载到进程的内存映射区也可以部分加载到进程的内存映射区,当进程A中的内存映射区数据被修改了,数据会被自动同步到磁盘文件,同时和磁盘文件建立映射关系的其他进程内存映射区中的数据也会和磁盘文件进行数据的实时同步,这个同步机制保障了各个进程之间的数据共享。
使用内存映射区既可以进程有血缘关系的进程间通信也可以进程没有血缘关系的进程间通信。创建内存映射区的函数原型如下:
123#include <sys/mman.h>// 创建内存映射区void *mmap(void *addr, si ...
1. 管道管道的是进程间通信(IPC - InterProcess Communication)的一种方式,管道的本质其实就是内核中的一块内存(或者叫内核缓冲区),这块缓冲区中的数据存储在一个环形队列中,因为管道在内核里边,因此我们不能直接对其进行任何操作。
因为管道数据是通过队列来维护的,我们先来分析一个管道中数据的特点:
管道对应的内核缓冲区大小是固定的,默认为4k(也就是队列最大能存储4k数据)
管道分为两部分:读端和写端(队列的两端),数据从写端进入管道,从读端流出管道。
管道中的数据只能读一次,做一次读操作之后数据也就没有了(读数据相当于出队列)。
管道是单工的:数据只能单向流动, 数据从写端流向读端。
对管道的操作(读、写)默认是阻塞的
读管道:管道中没有数据,读操作被阻塞,当管道中有数据之后阻塞才能解除
写管道:管道被写满了,写数据的操作被阻塞,当管道变为不满的状态,写阻塞解除
管道在内核中, 不能直接对其进行操作,我们通过什么方式去读写管道呢?其实管道操作就是文件IO操作,内核中管道的两端分别对应两个文件描述符,通过写端的文件描述符把数据写入到管道 ...
1. 进程概述从严格意义上来讲,程序和进程是两个不同的概念,他们的状态,占用的系统资源都是不同的。
程序:就是磁盘上的可执行文件文件, 并且只占用磁盘上的空间,是一个静态的概念。
进程:被执行之后的程序叫做进程,不占用磁盘空间,需要消耗系统的内存,CPU资源,每个运行的进程的都对应一个属于自己的虚拟地址空间,这是一个动态的概念。虚拟地址空间详解
1.1 并行和并发
CPU时间片
CPU在某个时间点只能处理一个任务,但是操作系统都支持多任务的,那么在计算机CPU只有一个的情况下是怎么完成多任务处理的呢?原理和古时候救济灾民的思路是一样的,每个人分一点,但是又不叫吃饱。
CPU会给每个进程被分配一个时间段,进程得到这个时间片之后才可以运行,使各个程序从表面上看是同时进行的。如果在时间片结束时进程还在运行,CPU的使用权将被收回,该进程将会被中断挂起等待下一个时间片。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换,这样就可以避免CPU资源的浪费。
因此可以得知,在我们使用的计算机中启动的多个程序,从宏观上看是同时运行的,从微观上看由于CPU一次只能处理一个进程,所有它们是轮流 ...
1. 本地软件安装1.1 MinGW 编译套件
GCC官方提供的编译套件不能直接在 windows 上使用,推荐的解决方案是使用 MinGW。
MinGW 提供了一套简单方便的 Windows 下的基于 GCC 程序开发环境,并且 收集了一系列免费的 Windows 使用的头文件和库文件。它整合了 GNU 的工具集,特别是 GNU 程序开发工具,如经典 gcc, g++, make 等。MinGW 是完全免费的自由软件,它在 Windows 平台上模拟了 Linux 下 GCC 的开发环境,为 C++ 的跨平台开发提供了良好基础支持,为了在 Windows 下工作的程序员熟悉 Linux 下的 C++ 工程组织提供了条件。
如果小伙伴本地安装了Qt,并且使用的编译套件也是 MingW,那么就不需要在安装了,配置一下环境变量即可。
Qt环境变量配置
如果本地没有,那就必须老老实实的下载一个了,下载地址如下:
MinGW官方下载地址: https://osdn.net/projects/mingw/
第一步, 运行下载到本地的 MinGW 下载器,准备编译套件的下载。
...
众所周知,Linux的目录是一个树状结构,了解数据结构的小伙伴都明白,遍历一棵树最简单的方式是递归。在我们已经掌握了递归的使用方法之后,遍历树状目录也不是一件难事儿。
Linux给我们提供了相关的目录遍历的函数,分别为:opendir(), readdir(), closedir()。目录的操作方式和标准C库提供的文件操作步骤是类似的。下面来依次介绍一下这几个函数。
1. 目录三剑客1.1 opendir
在目录操作之前必须要先通过 opendir() 函数打开这个目录,函数原型如下:
1234#include <sys/types.h>#include <dirent.h>// 打开目录DIR *opendir(const char *name);
参数: name -> 要打开的目录的名字
返回值: DIR*, 结构体类型指针。打开成功返回目录的实例,打开失败返回 NULL
1.2 readdir
目录打开之后,就可以通过 readdir() 函数遍历目录中的文件信息了。每调用一次这个函数就可以得到目录中的一个文件信息,当目录中的文件信息被全部 ...
Linux
未读在Linux中只要调用open()函数就可以给被操作的文件分配一个文件描述符,除了使用这种方式Linux系统还提供了一些其他的 API 用于文件描述符的分配,相关函数有三个:dup, dup2, fcntl。
1. dup1.1 函数详解dup函数的作用是复制文件描述符,这样就有多个文件描述符可以指向同一个文件了。函数原型如下:
12#include <unistd.h>int dup(int oldfd);
参数: oldfd 是要被复制的文件描述符
返回值:函数调用成功返回被复制出的文件描述符,调用失败返回 -1
下图展示了 dup()函数具体行为, 这样不过使用 fd1还是使用fd2都可以对磁盘文件A进行操作了。
被复制出的新文件描述符是独立于旧的文件描述符的,二者没有连带关系。也就是说当旧的文件描述符被关闭了,复制出的新文件描述符还是可以继续使用的。
1.2 示例代码下面的代码中演示了通过dup()函数进行文件描述符复制, 并验证了复制之后两个新、旧文件描述符是独立的,二者没有连带关系。
1234567891011121314151617181 ...
众所周知,Linux是一个基于文件的操作系统,因此作为文件本身也就有很多属性,如果想要查看某一个文件的属性有两种方式:命令和函数。虽然有两种方式但是它们对应的名字是相同的,叫做stat。另外使用file命令也可以查看文件的一些属性信息。
1. file 命令
该命令用来识别文件类型,也可用来辨别一些文件的编码格式。它是通过查看文件的头部信息来获取文件类型,而不是像Windows通过扩展名来确定文件类型的。
命令语法如下:
12# 参数在命令中的位置没有限制$ file 文件名 [参数]
file 命令的参数是可选项, 可以不加, 常用的参数如下表:
参数
功能
-b
只显示文件类型和文件编码, 不显示文件名
-i
显示文件的 MIME 类型
-F
设置输出字符串的分隔符
-L
查看软连接文件自身文件属性
1.1 查看文件类型和编码格式使用不带任何选项的 file 命令,即可查看指定文件的类型和文件编码信息。
123456789101112131415# 空文件$ file 11.txt 11.txt: empty# 源文件, 编码格式为: ASCII$ ...
Linux
未读每个系统都有自己的专属函数,我们习惯称其为系统函数。系统函数并不是内核函数,因为内核函数是不允许用户使用的,系统函数就充当了二者之间的桥梁,这样用户就可以间接的完成某些内核操作了。
在前面介绍了文件描述符,在Linux系统中必须要使用系统提供的IO函数才能基于这些文件描述符完成对相关文件的读写操作。这些Linux系统IO函数和标准C库的IO函数使用方法类似,函数名称也类似,下边开始一一介绍。
1. open/close1.1 函数原型
通过open函数我们即可打开一个磁盘文件,如果磁盘文件不存在还可以创建一个新的的文件,函数原型如下:
1234567891011121314#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>/*open是一个系统函数, 只能在linux系统中使用, windows不支持fopen 是标准c库函数, 一般都可以跨平台使用, 可以这样理解: - 在linux中 fopen底层封装了Linux的系统API open - 在window中, ...