1. 对于linux内核信号量,说法正确的是(多选):(参考:Linux内核设计与实现,第二版,第9章,9.4小节)
A. 如果获取一个被占用的信号量,任务会睡眠,等待信号量释放之后,该任务才能重新获得调度
B. 信号量可以允许任意数量的锁持有者
C. 信号量保护的代码可以被抢占
D. 信号量的实现也是与体系架构相关的
答案:A,B,C,D
试题解析:信号量是一个睡眠锁,在信号量被占用时,企图获取该信号量的任务会睡眠,等待信号量被释放,或者被唤醒,之后再重新获得调度;
信号量在初始化时,其count可以初始化为大于等于0的任何数值,因此可以允许任意数量的锁持有者;
信号量获取后,在释放之前,并不管抢占,正因为这个原因,在可抢占的内核中,高优先级任务可以抢占获取信号量的低优先级任务;
在内核中,信号量数据结构如下:
struct semaphore {
spinlock_t lock;
unsigned int count;
struct list_head wait_list;
};
自旋锁保护P/V(对其count加减)操作,而自旋锁是基于原子操作才能实现,因此信号量是与体系架构相关的。
2. 对于内核信号量,对其使用方法,错误的是(单选):(参考:Linux内核设计与实现,第二版,第9章,9.4小节)
A. 信号量在使用之前一定要初始化,否则在使用时可能会导致内核崩溃
B. 对信号量的操作,其实就是P/V操作,在linux内核中,对信号量的down()相当于V操作,up()相当于P操作
C. 在使用down_interruptible()函数未获取信号量时,进入睡眠的任务可以被信号唤醒
D. 如果想在获取信号量失败后超时退出,可以使用down_timeout()函数接口
答案:B
试题解析:内核信号量以及内核mutex,在使用之前都需要初始化,内核对信号量的初始化,方法有:
1. sema_init(struct semaphore *sem, int val),将count的值初始化为val;
2. init_MUTEX(sem), 将count的值初始化为1,通常用于互斥操作;
3. init_MUTEX_LOCKED(sem), 将count的值初始化为0,通常用于异步事件的同步;
在linux内核中,对信号量的down()相当于P操作,up()相当于V操作
down_interruptible()以及down_timeout()接口函数,可参考内核代码。
因此选B
3. 对于信号量和自旋锁使用区别,错误的是(单选):(参考:Linux内核设计与实现,第二版,第9章,9.4小节)
A. 信号量适合于多进程对资源互斥,竞争失败就会发生上下文切换,适合进程长时间占用资源;
B. 如果占用资源时间短于线程上下文切换开销时间,使用自旋锁
C. 在使用信号量和自旋锁时,持有信号量或者自旋锁的代码可以被高优先级任务抢占
D. 如果需要在中断上下文中保护临界区,则只能使用spinlock,不能使用信号量
答案:C
试题解析:信号量特点:
1. linux中的信号量是一种睡眠锁,当一个任务试图获得一个已经被占用的信号量,信号量会将其推进一个等待队列,然后让其睡眠。
2. 争用信号量的进程在等待锁可用时会睡眠,使用锁长时间持有的情况;
3. 允许任意数量持有该锁。
自旋锁特点:
1. 低开销加锁;
2. 短期锁定;
3. 可用于中断上下文中加锁;
4. 只允许一个任务获取。
自旋锁用于多核之间的同步,因此需要禁止抢占,否则很容易造成死锁(如在本地CPU上任务被抢占,在高优先级任务中又获取了同一个自旋锁,死锁)由此得出:C错误,获取自旋锁的代码不能被抢占。
4. 下面不是解决linux内核态并发机制的是(单选):(参考:Linux内核设计与实现,第二版,第9章)
A. 自旋锁;
B. 互斥锁mutex
C. 原子操作
D. 管道
答案:D。
试题解析:管道是一种用户态进程间通信机制。管道是进程之间的一个单向数据流:一个进程写入管道的所有数据都由内核定向到另一个进程,另一个进程由此就可以从管道中读取数据。
5. 下面不是内核态和用户态间通信机制的是(单选):(参考:)
A. Netlink;
B. 消息队列
C. 系统调用
D. ioctl
答案:B
试题解析:消息队列是一种用户态进程间通信机制,不能实现内核态和用户态间通信;
Netlink,系统调用,ioctl是使用较多的内核态和用户态间通信机制,其中系统调用只能由用户态发起。