> IT面试 >

关于linux内核的几个面试问题

1、Linux中主要有哪几种内核锁?

第一种:
//这里 val 是安排给旗标的初始值.
void sema_init(struct semaphore *sem, int val);
//结果是一个旗标变量( 称为 name ),
//初始化为 1 ( 使用 DECLARE_MUTEX ) 或者 0 (使用 DECLARE_MUTEX_LOCKED ).
DECLARE_MUTEX(name);
DECLARE_MUTEX_LOCKED(name);

// P 函数称为 down — 或者这个名子的某个变体
//这里, “down” 指的是这样的事实, 这个函数递减旗标的值
void down(struct semaphore *sem);
int down_interruptible(struct semaphore *sem);
int down_trylock(struct semaphore *sem);

//一旦调用down的时候 则不再拥有旗标
void up(struct semaphore *sem);

第二种: 读者 写着旗标
//初始化
void init_rwsem(struct rw_semaphore *sem);
//读者接口
// down_read 的调用提供了对被保护资源的只读存取
//与其他读者可能地并发地存取. 注意 down_read 可能将调用进程置为不可中断的睡眠
// down_read_trylock 如果读存取是不可用时不会等待; 如果被准予存取它返回非零, 否则是 0.
//注意 down_read_trylock 的惯例不同于大部分的内核函数, 返回值 0 指示成功
void down_read(struct rw_semaphore *sem);
int down_read_trylock(struct rw_semaphore *sem);
//释放
void up_read(struct rw_semaphore *sem);
//写者接口
void down_write(struct rw_semaphore *sem);
int down_write_trylock(struct rw_semaphore *sem);
//释放
void up_write(struct rw_semaphore *sem);
//你可以使用 downgrade_write 在一旦你已完成改变后允许其他读者
void downgrade_write(struct rw_semaphore *sem);

第三种:
// completion 是任务使用的一个轻量级机制: 允许一个线程告诉另一个线程工作已经完成.
//初始化
DECLARE_COMPLETION(my_completion);
或者, 如果 completion 必须动态创建和初始化:
struct completion my_completion;
/* … */
init_completion(&my_completion);

//等待 completion 是一个简单事来调用
void wait_for_completion(struct completion *c);

//如果多于一个线程在等待同一个 completion 事件, 这 2 个函数做法不同. complete 只唤醒一个等待的线程,
//而 complete_all 允许它们所有都继续. 在大部分情况下, 只有一个等待者, 这 2 个函数将产生一致的结果
void complete(struct completion *c);
void complete_all(struct completion *c);
//下面列一个example
DECLARE_COMPLETION(comp);
ssize_t complete_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)
{
printk(KERN_DEBUG “process %i (%s) going to sleep\n”,current->pid, current->comm);
wait_for_completion(&comp);
printk(KERN_DEBUG “awoken %i (%s)\n”, current->pid, current->comm);
return 0; /* EOF */
}
ssize_t complete_write (struct file *filp, const char __user *buf, size_t count, loff_t *pos)
{
printk(KERN_DEBUG “process %i (%s) awakening the readers…\n”, current->pid, current->comm);
complete(&comp);
return count; /* succeed, to avoid retrial */
}

//清理
void complete_and_exit(struct completion *c, long retval);

第四种: 自旋锁

//初始化spin_lock
spinlock_t my_lock = SPIN_LOCK_UNLOCKED;
//或者在运行时使用:
void spin_lock_init(spinlock_t *lock);
//在进入一个临界区前, 你的代码必须获得需要的 lock
void spin_lock(spinlock_t *lock);

//为释放一个你已获得的锁
void spin_unlock(spinlock_t *lock);

//实际上有 4 个函数可以加锁一个自旋锁:
void spin_lock(spinlock_t *lock);
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);
void spin_lock_irq(spinlock_t *lock);
void spin_lock_bh(spinlock_t *lock)

//也有 4 个方法来释放一个自旋锁
void spin_unlock(spinlock_t *lock);
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);
void spin_unlock_irq(spinlock_t *lock);
void spin_unlock_bh(spinlock_t *lock);
//还有一套非阻塞的自旋锁操作:
//这些函数成功时返回非零( 获得了锁 ), 否则 0. 没有”try”版本来禁止中断.
int spin_trylock(spinlock_t *lock);
int spin_trylock_bh(spinlock_t *lock);

2、Linux中的用户模式和内核模式是什么含意?

linux中内核本身处于内核模式,应用程序处于用户模式。

内核模式的代码可以无限制地访问所有处理器指令集以及全部内存和I/O空间。如果用户模式的进程要享有此特权,它必须通过系统调用向设备驱动程序或其他内核模式的代码发出请求。另外,用户模式的代码允许发生缺页,而内核模式的代码则不允许。

在2.4和更早的内核中,仅仅用户模式的进程可以被上下文切换出局,由其他进程抢占。除非发生以下两种情况,否则内核模式代码可以一直独占CPU:

(1) 它自愿放弃CPU;

(2) 发生中断或异常。

2.6内核引入了内核抢占,大多数内核模式的代码也可以被抢占。

3、用户进程间通信主要哪几种方式?

# 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
# 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
# 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
# 消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
# 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
# 共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
# 套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。

4、有哪几种内存分配函数?

(责任编辑:IT)