Posted in 面试题 onSeptember 25, 2012
1. 简述Sun Workshop中的几个重要概念:event/handler, watchpoint, RTC。
2. 简述Solaris所实现的系统接口标准(至少两种),并说明feature test macros的功能和使用方法。
unix 标准有:ANSI C, IEEE POSIX, X/OPEN XPG3 和 FIPS.实际应用的有:System V Release 4, 4.3+BSD.
feature test macro: 头文件中定义了很多宏,有POSIX,XPG3的。当程序编译时如果希望只使用POSIX的定义而不使用其它定义,
那么就需定义常数_ P O S I X _ S O U R C E。
当该常数定义时,就能排除其它专有的定义。
常数_ P O S I X _ S O U R C E 及其对应的常数_ X O P E N _ S O U R C E 被称之为功能测试宏(f e a t u r e
test macro )。所有功能测试宏都以下划线开始。当要使用它们时,通常在c c 命令行中以下列方
式定义:
cc -D_POSIX_SOURCE file.c
这使得在C 程序包括任何头文件之前,定义了功能测试宏。如果我们仅想使用P O S I X . 1 定义,那么也可将源文件的第一行设置为:
#define _POSIX_SOURCE 1
另一个功能测试宏是:_ _STDC_ _,它由符合ANSI C 标准的编译程序自动定义。
这样就允许我们编写ANSI C 编译程序和非ANSI C 编译程序都能编译的程序。
例如,一个头文件可能会是:
#ifdef __STDC__
void *myfunc(const char *, int);
#else
void *myfunc();
#endif
3. 试比较系统调用和库函数的区别(重点说明返回值和内存分配)。
system call 是用户访问内核系统服务的接口,使内核为调用线程执行某种特定的功能。
每个system call 在标准C 库中设置一个具有同样名字的函数。
用户进程用标准C 调用序列来调用这些函数,然后,函数又用系统所要求的技术调用相应的内核服务。
然后执行某个产生软中断进入内核的机器指令。是于平台相关的。
library function 是将system call进行封装后提供的接口。实际上,用户也可以定制自己的library function.
大体上,systerm call 实现内存的分配,library function 实现内存的管理。
当
1)library function在调用system call时,system call不会申请静态空间存放调用结果。Library function
应该申请动态空间,将地址作为参数传入。这时,system call将结果写在动态空间中。
2)library function在调用system call时,system call每次将结果放在固定的静态空间中。用户得到的返回值在静态空间中,
如果用户要多次调用该函数,则应申请动态空间,将返回值拷贝到动态空间中。在下次调用时,静态空间被重新赋值。
3)library function在调用system call时,system call每次都为用户进程申请动态空间,赋值,将动态空间地址返回给用户。
这种情况下,需要用户在使用完后,释放内存。
4. 简述Solaris的进程及两级线程模型,并说明概念-核心所支持的调度类。
进程是含有一个用户程序环境的抽象,包括虚存环境、程序所需资源以及至少一个执行线程。
每个进程中至少有一个轻量级线程,它是进程中每个内核线程的虚拟执行环境。
轻量级进程允许进程中的每个内核线程,获得与同一进程中的其他内核线程无关的系统调用。
虽然在统一进程内切换多个线程是不耗资源的,但线程的创建和消除却很耗资源。另外,进程中的内核线程要求有一个轻量级进程,它含有消耗内和资源的堆栈。
因此,在每个进程中增加了一级线程管理用户线程–二级线程模型。
见下图:
solaris的调度类有:
TS(分时)–它是进程和进程中所有内核线程的缺省调度类。他根据当前处理器的使用情况动态改变进程的优先级。
进程优先级和时间量在每个时钟滴答时,或在一个I/O引起睡眠后的唤醒期间,根据分时调度表计算。TS类的优先级由0-59。
IA(交互类,增强的TS类)–它是由桌面视窗系统使用得调度类。用来提高目的视窗中线程的优先级。
SYS(系统类)–内核线程使用的系统类。优先级60-99
RT(实时类)–用于实现固定的优先级、固定的时间量调度。优先级100-159
5. 当使用vfork()创建的新进程(没有调用exec或exec不成功)要退出时,我们一般调用_exit()函数,为什么?
v f o r k 用于创建一个新进程,而该新进程的目的是e x e c 一个新程序。v f o r k 与f o r k 一样都创建一个子进程,
但是它并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用e x e c (或e x i t ),
不过在子进程调用e x e c 或e x i t 之前,它在父进程的空间中运行。v f o r k 保证子进程先运行,在它调用e x e c 或e x i t 之后父进
程才可能被调度运行。
e x i t 和_ e x i t 函数用于正常终止一个程序:_ e x i t 立即进入内核,e x i t 则先执行一些清除处理(包括调用执行各终止处理程序,关闭所有标准I / O 流等),然后进入内核。
_ e x i t 并不执行标准I / O 缓存的刷新操作。
如果用e x i t 而不是_ e x i t ,它刷新开关闭了所有标准I / O 流,这包括标准输出。
虽然这是由子进程执行的,但却是在父进程的地址空间中进行的,所以所有受到影响的标准I/O FILE 对象都是在父进程中的。
6. 什么是“zombie”进程?在我们的程序中如何防止“zombie”进程?(试说出其中的三种方法)
一个已经终止、但是其父进程尚未对其进行善后处理(获取终止子进程的有关信息、释放它仍占用的资源)的进程被称为僵死进程(z o m b i e )。
避免z o m b i e 的方法:
(1)在S V R 4 中,如果调用s i g n a l 或s i g s e t 将S I G C H L D 的配置设置为忽略,则不会产生僵死子进程。另外,使用S V R 4 版的s i g a c t i o n ,则可设置S A _ N O C L D WA I T 标
志(见表1 0 – 5 )以避免子进程僵死。(10.7)
(2)调用f o r k两次。程序8 – 5 实现了这一点。
(3)用waitpid等待子进程返回.
7. 以下代码是不可靠信号处理的经典例子之一,试说明其中的问题(包括细节):
8. 在信号(Signal)处理中,我们必须注意两个重要的问题:可重启动的系统调用和可重入函数。试说明以下两个问题:
a) 在Solaris中如何设置可重启动的系统调用标志(提示:使用sigaction)。
b) 什么是异步事件安全(Asyn-signal safe)函数?举例说明异步事件不安全的函数(即一般在信号处理程序中不能调用的函数)。(例外,提醒大家:在信号处理程序中注意保存errono)。
9. 在使用Pthread时,典型的代码如下:
pthread_attr_init( &attr );/* initialize attr with default attributes */
pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM );
pthread_create( &tid, &attr, start_func, arg );
说明以上代码中的PTHREAD_SCOPE_SYSTEM所代表的含义。
10. 在Solaris中,用于线程间同步的机制主要包括:POSIX互斥锁(Mutex Lock)、POSIX读写锁(read-write lock)、POSIX信号量(semaphore)和POSIX条件变量(condition variable)。试简要说明以上几种同步机制的主要用途和区别。
11. 在Solaris中,POSIX互斥锁主要用于线程间同步。说明POSIX互斥锁用于进程间同步时的主要步骤。(提示:使用系统调用mmap and ftruncate, 注意cleanup)。
◆ 互斥锁
互斥锁(mutex)使得某一确定时刻只有一个线程可以访问保护中的数据。
◆ 读/写锁
采用读写锁,允许多个线程同时读访问共享数据区,但是只能有一个线程写访问
共享数据区。
绝大多数设备驱动程序不使用读写锁。这种锁比互斥锁慢,仅当经常出现多个线
程需要同时读访问共享数据而同时较少有写访问时,才采用读写锁,互斥锁此时可能
导致写访问延迟。参看rwlock(9F)了解更多信息。
◆ 信号灯
信号灯也是设备驱动程序编写中一种可选的线程同步机制,参看semaphore(9F)
了解更多细节。
◆ 线程同步
除了需要保护共享数据区外,驱动程序经常需要保持多线程同步执行。
◆ 条件变量
条件变量是线程同步的标准形式,与互斥锁配合使用。互斥锁用于确保检查条件
变量时是原子的,如果被检查的条件变量无变化则线程阻塞,等待条件变量变化信号
的唤醒。必须调用cv_init(9F)初始化条件变量,调用cv_destroy(9F)摧毁条件变量。
注意:条件变量例程类似SunOS 4.1中的sleep()和wakeup()例程。
代码举例 使用互斥锁和条件变量
————————————————————————–
static int xxread ( dev_t dev, struct uio * uiop, cred_t * credp )
{
struct xxstate * xsp;
…
mutex_enter( &xsp->mu );
while ( xsp->busy )
{
cv_wait( &xsp->cv, &xsp->mu );
}
xsp->busy = 1;
mutex_exit( &xsp->mu );
perform the data access
} /* end of xxread */
static u_int xxintr ( caddr_t arg )
{
struct xxstate * xsp = ( struct xxstate * )arg;
mutex_enter( &xsp->mu );
xsp->busy = 0;
cv_broadcast( &xsp->cv );
mutex_exit( &xsp->mu );
} /* end of xxintr */
————————————————————————–
12. 编写一个小程序,输入参数为一个文件名,它的功能描述如下:
a) 测试此文件是否为符号连接;如果不是,则打印错误信息后退出;
b) 读出此符号连接所指目标文件的文件名;
c) 测试此符号连接所指目标文件是否存在于文件系统中。
(提示:使用lstat, readlink)。
13. 说明基于TCP协议的服务器和客户端的主要步骤,重点阐明服务器和客户端的配合关系。(提示:可以使用时序图标明配合关系)。
2. 简述Solaris所实现的系统接口标准(至少两种),并说明feature test macros的功能和使用方法。
unix 标准有:ANSI C, IEEE POSIX, X/OPEN XPG3 和 FIPS.实际应用的有:System V Release 4, 4.3+BSD.
feature test macro: 头文件中定义了很多宏,有POSIX,XPG3的。当程序编译时如果希望只使用POSIX的定义而不使用其它定义,
那么就需定义常数_ P O S I X _ S O U R C E。
当该常数定义时,就能排除其它专有的定义。
常数_ P O S I X _ S O U R C E 及其对应的常数_ X O P E N _ S O U R C E 被称之为功能测试宏(f e a t u r e
test macro )。所有功能测试宏都以下划线开始。当要使用它们时,通常在c c 命令行中以下列方
式定义:
cc -D_POSIX_SOURCE file.c
这使得在C 程序包括任何头文件之前,定义了功能测试宏。如果我们仅想使用P O S I X . 1 定义,那么也可将源文件的第一行设置为:
#define _POSIX_SOURCE 1
另一个功能测试宏是:_ _STDC_ _,它由符合ANSI C 标准的编译程序自动定义。
这样就允许我们编写ANSI C 编译程序和非ANSI C 编译程序都能编译的程序。
例如,一个头文件可能会是:
#ifdef __STDC__
void *myfunc(const char *, int);
#else
void *myfunc();
#endif
3. 试比较系统调用和库函数的区别(重点说明返回值和内存分配)。
system call 是用户访问内核系统服务的接口,使内核为调用线程执行某种特定的功能。
每个system call 在标准C 库中设置一个具有同样名字的函数。
用户进程用标准C 调用序列来调用这些函数,然后,函数又用系统所要求的技术调用相应的内核服务。
然后执行某个产生软中断进入内核的机器指令。是于平台相关的。
library function 是将system call进行封装后提供的接口。实际上,用户也可以定制自己的library function.
大体上,systerm call 实现内存的分配,library function 实现内存的管理。
当
1)library function在调用system call时,system call不会申请静态空间存放调用结果。Library function
应该申请动态空间,将地址作为参数传入。这时,system call将结果写在动态空间中。
2)library function在调用system call时,system call每次将结果放在固定的静态空间中。用户得到的返回值在静态空间中,
如果用户要多次调用该函数,则应申请动态空间,将返回值拷贝到动态空间中。在下次调用时,静态空间被重新赋值。
3)library function在调用system call时,system call每次都为用户进程申请动态空间,赋值,将动态空间地址返回给用户。
这种情况下,需要用户在使用完后,释放内存。
4. 简述Solaris的进程及两级线程模型,并说明概念-核心所支持的调度类。
进程是含有一个用户程序环境的抽象,包括虚存环境、程序所需资源以及至少一个执行线程。
每个进程中至少有一个轻量级线程,它是进程中每个内核线程的虚拟执行环境。
轻量级进程允许进程中的每个内核线程,获得与同一进程中的其他内核线程无关的系统调用。
虽然在统一进程内切换多个线程是不耗资源的,但线程的创建和消除却很耗资源。另外,进程中的内核线程要求有一个轻量级进程,它含有消耗内和资源的堆栈。
因此,在每个进程中增加了一级线程管理用户线程–二级线程模型。
见下图:
solaris的调度类有:
TS(分时)–它是进程和进程中所有内核线程的缺省调度类。他根据当前处理器的使用情况动态改变进程的优先级。
进程优先级和时间量在每个时钟滴答时,或在一个I/O引起睡眠后的唤醒期间,根据分时调度表计算。TS类的优先级由0-59。
IA(交互类,增强的TS类)–它是由桌面视窗系统使用得调度类。用来提高目的视窗中线程的优先级。
SYS(系统类)–内核线程使用的系统类。优先级60-99
RT(实时类)–用于实现固定的优先级、固定的时间量调度。优先级100-159
5. 当使用vfork()创建的新进程(没有调用exec或exec不成功)要退出时,我们一般调用_exit()函数,为什么?
v f o r k 用于创建一个新进程,而该新进程的目的是e x e c 一个新程序。v f o r k 与f o r k 一样都创建一个子进程,
但是它并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用e x e c (或e x i t ),
不过在子进程调用e x e c 或e x i t 之前,它在父进程的空间中运行。v f o r k 保证子进程先运行,在它调用e x e c 或e x i t 之后父进
程才可能被调度运行。
e x i t 和_ e x i t 函数用于正常终止一个程序:_ e x i t 立即进入内核,e x i t 则先执行一些清除处理(包括调用执行各终止处理程序,关闭所有标准I / O 流等),然后进入内核。
_ e x i t 并不执行标准I / O 缓存的刷新操作。
如果用e x i t 而不是_ e x i t ,它刷新开关闭了所有标准I / O 流,这包括标准输出。
虽然这是由子进程执行的,但却是在父进程的地址空间中进行的,所以所有受到影响的标准I/O FILE 对象都是在父进程中的。
6. 什么是“zombie”进程?在我们的程序中如何防止“zombie”进程?(试说出其中的三种方法)
一个已经终止、但是其父进程尚未对其进行善后处理(获取终止子进程的有关信息、释放它仍占用的资源)的进程被称为僵死进程(z o m b i e )。
避免z o m b i e 的方法:
(1)在S V R 4 中,如果调用s i g n a l 或s i g s e t 将S I G C H L D 的配置设置为忽略,则不会产生僵死子进程。另外,使用S V R 4 版的s i g a c t i o n ,则可设置S A _ N O C L D WA I T 标
志(见表1 0 – 5 )以避免子进程僵死。(10.7)
(2)调用f o r k两次。程序8 – 5 实现了这一点。
(3)用waitpid等待子进程返回.
7. 以下代码是不可靠信号处理的经典例子之一,试说明其中的问题(包括细节):
8. 在信号(Signal)处理中,我们必须注意两个重要的问题:可重启动的系统调用和可重入函数。试说明以下两个问题:
a) 在Solaris中如何设置可重启动的系统调用标志(提示:使用sigaction)。
b) 什么是异步事件安全(Asyn-signal safe)函数?举例说明异步事件不安全的函数(即一般在信号处理程序中不能调用的函数)。(例外,提醒大家:在信号处理程序中注意保存errono)。
9. 在使用Pthread时,典型的代码如下:
pthread_attr_init( &attr );/* initialize attr with default attributes */
pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM );
pthread_create( &tid, &attr, start_func, arg );
说明以上代码中的PTHREAD_SCOPE_SYSTEM所代表的含义。
10. 在Solaris中,用于线程间同步的机制主要包括:POSIX互斥锁(Mutex Lock)、POSIX读写锁(read-write lock)、POSIX信号量(semaphore)和POSIX条件变量(condition variable)。试简要说明以上几种同步机制的主要用途和区别。
11. 在Solaris中,POSIX互斥锁主要用于线程间同步。说明POSIX互斥锁用于进程间同步时的主要步骤。(提示:使用系统调用mmap and ftruncate, 注意cleanup)。
◆ 互斥锁
互斥锁(mutex)使得某一确定时刻只有一个线程可以访问保护中的数据。
◆ 读/写锁
采用读写锁,允许多个线程同时读访问共享数据区,但是只能有一个线程写访问
共享数据区。
绝大多数设备驱动程序不使用读写锁。这种锁比互斥锁慢,仅当经常出现多个线
程需要同时读访问共享数据而同时较少有写访问时,才采用读写锁,互斥锁此时可能
导致写访问延迟。参看rwlock(9F)了解更多信息。
◆ 信号灯
信号灯也是设备驱动程序编写中一种可选的线程同步机制,参看semaphore(9F)
了解更多细节。
◆ 线程同步
除了需要保护共享数据区外,驱动程序经常需要保持多线程同步执行。
◆ 条件变量
条件变量是线程同步的标准形式,与互斥锁配合使用。互斥锁用于确保检查条件
变量时是原子的,如果被检查的条件变量无变化则线程阻塞,等待条件变量变化信号
的唤醒。必须调用cv_init(9F)初始化条件变量,调用cv_destroy(9F)摧毁条件变量。
注意:条件变量例程类似SunOS 4.1中的sleep()和wakeup()例程。
代码举例 使用互斥锁和条件变量
————————————————————————–
static int xxread ( dev_t dev, struct uio * uiop, cred_t * credp )
{
struct xxstate * xsp;
…
mutex_enter( &xsp->mu );
while ( xsp->busy )
{
cv_wait( &xsp->cv, &xsp->mu );
}
xsp->busy = 1;
mutex_exit( &xsp->mu );
perform the data access
} /* end of xxread */
static u_int xxintr ( caddr_t arg )
{
struct xxstate * xsp = ( struct xxstate * )arg;
mutex_enter( &xsp->mu );
xsp->busy = 0;
cv_broadcast( &xsp->cv );
mutex_exit( &xsp->mu );
} /* end of xxintr */
————————————————————————–
12. 编写一个小程序,输入参数为一个文件名,它的功能描述如下:
a) 测试此文件是否为符号连接;如果不是,则打印错误信息后退出;
b) 读出此符号连接所指目标文件的文件名;
c) 测试此符号连接所指目标文件是否存在于文件系统中。
(提示:使用lstat, readlink)。
13. 说明基于TCP协议的服务器和客户端的主要步骤,重点阐明服务器和客户端的配合关系。(提示:可以使用时序图标明配合关系)。
一些Unix笔试题和面试题
声明:登载此文出于传递更多信息之目的,并不意味着赞同其观点或证实其描述。
Tags in this post...
Reply on: @reply_date@
@reply_contents@