1. 标准IO和文件IO的区别是什么?
2. 静态库和动态库的区别?
3. 什么是孤儿进程?什么是僵尸进程?
4. 什么是守护进程?步骤?
5. 进程和线程区别?
6. 线程的同步与互斥?
7.实现同步机制的几种方式?
8. 进程间通信方式都有哪些?
9. 无名管道和有名管道的区别?
10. 共享内存、信号灯集、消息队列步骤、函数?
前言:
这里分享一下IO进程相关的面试问答知识,网络IO知识点不需要你背的一字不落,最重要的是理解。就是你看懂每个IO的原理,然后用自己的语言表述出来,并且要把面试官讲懂。再进一步,让一个完全不懂计算机的人也能弄懂。
1. 标准IO和文件IO的区别是什么?
标准IO | 文件IO | |
定义 | 在C库中定义的一组输入输出的函数 | 在posix中定义的一组输入输出的函数 |
特点 | 有缓冲机制 围绕流进行操作,FILE* 默认打开三个流 : stdin/stdout/stderr 只能操作普通文件 | 没有缓冲机制 围绕文件描述符操作,int 默认打开三个文件描述符:0/1/2 操作除d外任意类型文件 |
函数 | 打开文件:fopen/freopen 关闭文件:fclose 读写文件:fgetc/fputc、fgets/fputs、fread/fwrite 文件定位:fseek\rewind\ftell | 打开文件:open 关闭文件:close 读写文件:read、write 文件定位:lseek |
2. 静态库和动态库的区别?
静态库和动态库,本质区别是代码被载入时刻不同。
1) 静态库在程序编译时会被连接到目标代码中。
优点:程序运行时将不再需要该静态库;运行时无需加载库,运行速度更快
缺点:静态库中的代码复制到了程序中,因此体积较大;
静态库升级后,程序需要重新编译链接
2) 动态库是在程序运行时才被载入代码中。
优点:程序在执行时加载动态库,代码体积小;
程序升级更简单;
不同应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。
缺点:运行时还需要动态库的存在,移植性相对于静态库较差
3. 什么是孤儿进程?什么是僵尸进程?
1)子进程几乎拷贝了父进程的全部内容。包括代码、数据、系统数据段中的pc值、栈中的数据、父进程中打开的文件等;但它们的PID、PPID是不同的。
2)父子进程有独立的地址空间,互不影响;当在相应的进程中改变全局变量、静态变量,都互不影响。
3)若父进程先结束,子进程成为孤儿进程,被init进程收养,子进程变成后台进程。
4)若子进程先结束,父进程如果没有及时回收,子进程变成僵尸进程(要避免僵尸进程产生
4. 什么是守护进程?步骤?
特点:守护进程是后台进程;生命周期比较长,从系统启动时开启,系统关闭时结束;它是脱离控制终端且周期执行的进程。
步骤:
1) 创建子进程,父进程退出
让子进程变成孤儿进程,成为后台进程;fork()
2) 在子进程中创建新会话
让子进程成为会话组组长,为了让子进程完全脱离终端;setsid()
3) 改变进程运行路径为根目录
原因进程运行的路径不能被删除或卸载;chdir("/")
4) 重设文件权限掩码
目的:增大进程创建文件时权限,提高灵活性;umask(0)
5) 关闭文件描述符
将不需要的文件关闭;close()
5. 进程和线程区别?
共性:都为操作系统提供了并发执行能力
不同点:
调度和资源:线程是系统调度的最小单位,进程是资源分配的最小单位
地址空间方面:同一个进程创建的多个线程共享进程的资源;进程的地址空间相互独立
通信方面:线程通信相对简单,只需要通过全局变量可以实现,但是需要考虑临界资源访问的问题;进程通信比较复杂,需要借助进程间的通信机制(借助3g-4g内核空间)
安全性方面:线程安全性差一些,当进程结束时会导致所有线程退出;进程相对安全
6. 线程的同步与互斥?
线程同步:每个线程之间按预定的先后次序进行运行,协同、协助、互相配合。可以理解成“你说完,我再做”。有了线程同步,每个线程才不是自己做自己的事情,而是协同完成某件大事。
线程互斥:当有若干个线程访问同一块资源时,规定同一时间只有一个线程可以得到访问权,其它线程需要等占用资源者释放该资源才可以申请访问。线程互斥可以看成是一种特殊的线程同步。
7.实现同步机制的几种方式?
互斥锁+条件变量、信号、信号量、信号灯集
8. 进程间通信方式都有哪些?
1:早期进程间通信:无名管道、有名管道、信号
system V IPC 对象:共享内存、信号灯集、消息队列
BSD:socket
9. 无名管道和有名管道的区别?
无名管道 | 有名管道 | |
使用场景 | 亲缘关系 | 不相关进程 |
特点 | 半双工 固定的读端和写端 被看作特殊的文件,通过文件IO进行操作 不是文件 | 半双工 在文件系统中可见,数据存放在内存 文件IO操作 不支持lseek()操作,遵循先进先出 |
函数 | pipe() 直接read、write | mkfifo() 先open打开,在进行read、write |
读写特性 | 当无名管道无数据,读阻塞 当无名管道中写满64k,写阻塞 读端关闭,继续写数据会造成管道破裂 | 只写方式,写阻塞,直到另一个进程把读打开 只读方式,读阻塞,直到另一个进程把写打开 可读可写,管道中无数据时,读阻塞 |
10. 共享内存、信号灯集、消息队列步骤、函数?
共享内存
创建或打开共享内存shmget
映射共享内存到用户空间shmat
取消映射shmdt
删除共享内存 shmctl
信号灯集
1)创建或打开信号灯集。Semget
shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0666);
semid = semget(key, 1, IPC_CREAT|IPC_EXCL|0666);
p = (char *)shmat(shmid, NULL, 0);//NULL:系统自动完成映射 0:可读可写
2)初始化。semctl
3)PV操作。semop
4)删除信号灯集。Semctl
struct sembuf sem;
sem.sem_num = num; //信号灯的编号
sem.sem_op = op; //p操作,申请资源
sem.sem_flg = 0; //阻塞
semop(semid, &sem, 1); //1:操作的信号灯的个数
消息队列
创建或打开消息队列msgget。
添加消息:按照类型把消息添加到已打开的消息队列末尾msgsnd。
读取消息:可以按照消息类型将消息从消息队列中读走msgrcv。
删除消息队列 msgctl。