linux同步机制2

一.并发控制

(1)自旋锁

得不到资源,会原地打转,直到获得资源为止

定义自旋锁

spinlock_t spin;

初始化自旋锁

spin_lock_init(lock);

获得自旋锁

spin_lock(lock);获得自旋锁,如果能立即获得,则马上返回,否则自旋在那里,直到该自旋锁的保持者释放

spin_trylock(lock);尝试获得自旋锁,如果能立即获得,它获得并返回真,否则立即返回假,实际上,不再“在原地打转”

释放自旋锁

spin_unlock(lock);与spin_trylock或者spin_lock配对使用

使用方法:

spinlock_t lock;

spin_lock_init(&lock);

spin_lock(&lock);//获取自旋锁,保护临界区

...//临界区

spin_unlock(&lock);//解锁

eg:使用自旋锁使设备只能被一个进程打开

int xxx_count=0;

static int xxx_open(struct inode *inode, struct file *filp)

{

...

spinlock(&xxx_lock);

if(xxx_count)

{

spin_unlock(&xxx_lock);

return -EBUSY;

}

xxx_count++;

spin_unlock(&xxx_lock);

...

return 0;

}

static int xxx_release(struct inode *inode,struct file *filp)

{

...

spinlock(&xxx_lock);

xxx_count--;

spin_unlock(&xxx_lock);

return 0;

}

(2)信号量

得不到资源,会进入休眠状态

定义信号量

struct semaphore sem;

初始化信号量

void sema_init(struct semaphore *sem,int val);初始化并设置为val

void init_MUTEX(struct semaphore *sem);初始化并设置为1

void init_MUTEX_LOCKED(struct semaphore *sem);初始化并设置为0

下面两个宏用于定义并初始化信号量的“快捷方式”

DECLARE_MUTEX(name);初始化并设置为1

DECLARE_MUTEX_LOCKED(name);初始化并设置为0

获得信号量

void down(struct semaphore *sem);会导致休眠,不能在中断上下文使用

int down_interruptible(struct semaphore *sem);不会导致休眠,可在中断上下文使用

使用down_interruptible()获得信号量时,常对返回值进行检查

if(down_interruptible(&sem))

{

return -ERESTARTSYS;

}

释放信号量

void up(struct semaphore *sem);释放信号量sem,唤醒等待者

使用方法:

DECLARE_MUTEX(mount_sem);

down(&mount_sem);获取信号量,保护临界区

...

critical section //临界区

...

up(&mount_sem);//释放信号量

eg:使用信号量实现设备只能被一个进程打开

static DECLARE_MUTEX(xxx_lock);//定义互斥锁

static int xxx_open(struct inode *inode,struct file *filp)

{

...

if(down_trylock(&xxx_lock))//获得打开锁

return -EBUSY;//设备忙

...

return 0;

}

static int xxx_release(struct inode *inode,struct file *filp)

{

up(&xxx_lock);//释放打开锁

return 0;

}

总结:在多CPU中需要自旋锁来互斥,当进程占用资源时间较长,使用信号量。当所要保护的临界区访问时间较短,用自旋锁,它节省了上下文切换的时间。

信号量所保护的临界区可包含可能引起阻塞的代码,自旋锁不能包含。阻塞意味着进行进程的切换,如果进程被切换出去后,另一个进程企图获取本自旋锁,死锁会发生。

信号量存在进程上下文,如果被保护的共享资源需要在中断或软中断情况下使用,只能使用自旋锁,如果一定要使用信号量,只能通过down_trylock()方式进行,不能获取就立即返回避免阻塞。

自旋锁会导致死循环,锁定期间不允许阻塞,锁定的临界区要小。

(3)互斥体

信号量已经可以实现互斥的功能,但是mutex还是在linux中真实存在

定义并初始化

struct mutex my_mutex;

mutex_init(&my_mutex);

获取互斥体

void fastcall mutex_lock(struct mutex *lock);

int fastcall mutex_lock_interruptible(strutct mutex *lock);

int fastcall mutex_trylock(struct mutex *lock);

释放互斥体

void fastcall mutex_unlock(struct mutex *lock);

使用方法

struct mutex my_mutex;

mutex_init(&my_mutex);

mutex_lock(&my_mutex);

...//临界资源

mutex_unlock(&my_mutex);