Unix环境解疑

Unix环境高级编程一直是介绍Unix系统方面的经典,这个假期把它温习了一遍,现将重点和基础的东西记录下来,不 枉白看一本好书。

文件共享是怎么回事?

在理解文件共享前先必须知道:

1. 每个进程在进程表中都会有一个记录项,记录项中包含一个打开文件描述符表,它通过文件描述符fd与内核中的文件表关联起来。

2. 内核为每个打开的文件维持一张表,它记录文件的状态、文件偏移量及文件v节点表项的指针。

3. 对于每个被打开的文件v节点唯一,在linux中使用的是i节点。

那么两个进程间的文件共享会有哪些形式呢?下面两点需要记住:

1. 如果两个独立进程打开同一个文件,内核为其建立的文件表项是不同的。

2. 如果使用dup复制文件描述符或者使用fork系统调用后,会共享内核建立的文件表项。

标准IO的缓冲形式有哪些?

标准IO是流式IO,它通过操作文件描述符来操作文件,我们知道的文件读写函数read及write都是系统调用,我们可 以为其指定缓冲区的大小,那么标准IO的缓冲又是怎样一种形式呢?

1. 全缓冲,这种情况下,一般填满整个缓冲区后才会发生真正的IO操作,当然我们可以调用flush函数将缓冲区的数据冲洗到磁盘上面。

2. 行缓冲,当输入或者输出遇到换行符时,标准IO执行IO操作。这个时候就会遇到这个问题,一般标准IO收集每一行的缓冲区的长度是固定的,所以这个缓冲区被填满也会发生IO操作,一般涉及终端设备的流是行缓冲的。

3. 不带缓冲,最典型的例子就是标准出错流stderr,只要流中出现字符即被冲洗到文件中。

标准IO库看起来是多以f开头的函数,由于其本身提供了一层缓冲,导致数据会被多次复制,这可能是它效率不高的 原因之一,一般使用标准IO函数时,数据通常会被复制两次,一次是在标准IO缓冲区和用户空间缓冲区之间,二是 在内核和标准IO缓冲区之间(调用read及write时),显然内核还会提供一层缓冲。

进程与线程关系如何?

进程与线程的关系要理清楚是一件很困难的事情,特别是各个unix-like系统的实现方式各不一样,我们先来说说进程 的结构组成,由低地址到高地址分别是程序正文、初始化的数据(由exec从程序文件中读入)、未初始化数据(由 exec初始化为0)、堆(由低往高增长)、栈(由高地址往低处增长)、命令行参数和环境变量,注意:这些地址都是 进程的虚地址空间(各进程相互独立),其空间一般是固定大小的,范围可以很大。

unix进程都会有一个控制线程,在传统情况下,一个进程在同一时刻只做一件事情,如果有多个控制线程,就可以 用一个进程来同时完成不同的工作,进程的地址空间对于线程来说是可见的。而linux对待线程的方式却不一样,它 使用clone系统调用来实现pthread_create,clone系统调用创建子进程,子进程与父进程共享一部分执行环境(如文 件描述符和内存),所以linux几乎将进程和线程同等对待,一个进程包含多个线程的模型被改造成了多个进程通过 共享大部分执行环境来实现,其实这就是LWP(轻量级进程)的实现思想。

信号是针对进程的概念,如果信号的默认动作是终止该进程,那么把信号传递给某个线程仍然会杀死整个进程,闹钟 定时器是所有线程共享的进程资源,所以进程中多个线程不可能互不干扰地使用闹钟定时器。不过这些情况对于linux 是否成立?有待实践地检验。

为什么需要IO多路转接?

在一个进程中使用阻塞IO的形式读一个描述符的例子随处可见,那么当我们需要读两个描述符的时候,不可能在一个 控制线程的情况下阻塞两个描述符(当然可以使用非阻塞轮询的方式),这里自然而然想到的解决办法就是使用两 个控制线程,一个线程等待阻塞一个描述符。但是使用另一种技术-IO多路转接的效率会更高。

select就是实现IO多路转接的函数,它将进程关心的文件描述符(通常是网络套接字或终端设备)和对于每个描述符 我们所关心的状态告诉内核,当有事件发生的时候,select返回准备好的描述符数,如果返回0则表示没有描述符准 备好,由于select只是返回一个int值即准备好的描述符数目,则我们并不能精确判断到底是哪些描述符发生了状态 改变,而epoll能做到这一点,所以select已经被epoll取代了。

进程间IPC如何选择?

进程间通信有很多种方法,如:管道、FIFO、消息队列、信号量、共享存储和套接字。使用最为广泛的当然是管道 和套接字。

如果我们需要考虑两个父子进程之间的通信问题时,首要选择当然是管道,一般它是半双工的,就是我们建立一条 管道需要在父(子)进程中关闭读(写)端,在子进程中亦然。

如何两个进程之间没有公共祖先,那么我们就不能使用管道了,这个时候套接字将成为首选。如果两个进程处于同 一台主机上,一般选择unix域套接字,虽然因特网套接字能达到同一目的,但是UNIX域套接字的效率更高,因为其 不需要添加或删除网络报头,无需计算检验和,不要产生顺序号,无需发送确认报文。

如果两个不同主机上的进程之间通信,没有话说,当然是使用因特网套接字,其它的进程间IPC使用的比较少。我们 在编写服务器端监听程序的时候,如果是TCP协议,每个套接字会绑定一个连接,套接字地址是主机和端口号标识的, 而服务器需要接收多个连接,所以accept函数每次返回一个新的套接字来保持连接,而新套接字和原始的套接字保持 着相同的套接字类型和地址族。



Previous     Next
zhing /
Published under (CC) BY-NC-SA in categories linux  tagged with linux