信号量一般又叫做信号灯,协调不同进程间的数据对象的,本质上是一个计数器,记录对某个资源(共享内存)的存取情况。


从定义来看,信号量底层使用到了spin lock的锁定机制,这个spinlock主要用来确保对count成员的原子操作


使用的大致方式:


1)测试控制该资源的信号量


2)若此信号量为正,允许使用,进程将信号量-1


3)若信号量=0,则不可使用,进程进入睡眠状态,直到信号量大于0,进程被resume,jump to step1).


4)但进程不再使用一个信号量控制资源时,信号量+1,测试如果有进程正在等待此信号量,唤醒此进程。


解释:


信号量的获取:


( 1 ). void down( struct semaphore *sem); //废弃



在保证原子操作的前提下,先测试count是否大于0, ~ 如果是说明可以获得信号量,这种情况下需要先将count--,以确保别的进程能否获得该信号量,然后函数返回,其调用者开始进入临界区。 ~ 如果没有获得信号量,当前进程利用struct semaphore 中wait_list加入等待队列,开始睡眠。


( 2 ). int down_interruptible( struct semaphore *sem);



/* 试图去获得一个信号量,如果没有获得,函数立刻返回1而不会让当前进程进入睡眠状态。 */  


( 3 ). int down_trylock( struct semaphore *sem);



/* 如果没有其他线程等待在目前即将释放的信号量上,那么只需将count++即可。如果有其他线程正因为等待该信号量而睡眠,那么调用__up唤醒睡眠的进程*/  


void up( struct semaphore *sem);    //信号量的释放



互斥锁:


互斥主要现在了互相排斥(mutual exclusion)同步的简单形式,所以也叫mutex(互斥体)。


互斥体禁止多个线程同时进入受保护的代码临界区。因此,任何时刻,只有一个线程被允许进入这样的代码保护区


mutex实际上是count=1情况下的semaphore。而我们开发用的最多的锁就是mutex。



// 定义互斥锁lock
 
mutex_init( 
 struct 
  mutex* 
  lock 
 )
 
// 获取
 
mutex_lock( 
 struct 
  mutex * 
 lock 
 )
 
// 释放
 
mutex_unlock( 
 struct 
  mutex * 
 lock 
 )
 
 
 
 
// 结构 
  struct 
  mutex { 
  
 
/* 1: unlocked, 0: locked, negative: locked, possible waiters */
 
atomic_t count; 
 
spinlock_t wait_lock; 
  
 
struct 
  list_head wait_list;
 
#ifdef CONFIG_DEBUG_MUTEXES 
  struct 
  thread_info *owner; 
  
 
const 
  char 
  *name; 
  void 
  *magic; 
  
 
#endif 
  
 
#ifdef CONFIG_DEBUG_LOCK_ALLOC 
  struct 
  lockdep_map dep_map;
 
#endif
 
};



自旋锁:


任何时刻,最多只能有一个保持者


区别于mutex:


对于mutex,如果资源已经被占用,资源的申请者只能进入suspend状态


但是自旋锁不会引起调用者suspend,如果自旋锁已经被别的单元持有,调用者会一直循环查看该锁是否释放(自旋的含义)


最大的区别,自旋锁不会suspend



结构:


# linux/Spinlock.h 
  
 
typedef 
  struct 
  spinlock { 
 
union { 
  //联合 
  
 
struct 
  raw_spinlock rlock; 
  
 
#ifdef CONFIG_DEBUG_LOCK_ALLOC 
  
 
# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))
 
struct 
 { u8 __padding[LOCK_PADSIZE]; 
  struct 
  lockdep_map dep_map;
 
};
 
#endif 
  
 
};
 
} spinlock_t;
 
 
 
 
init:
 
spinlock_t my_lock = SPIN_LOCK_UNLOCKED;
 
void 
  spin_lock_init(spinlock_t * 
 lock 
 );



自旋锁和互斥锁的对比:


信号量量/互斥体 允许进程睡眠属于 睡眠锁 ,自旋锁则 不允许调用者睡眠 ,而是让其 循环等待 ,所以有以下区别应用  


1)、信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因而自旋锁适合于保持时间非常短的情况  


2)、 自旋锁可以用于中断,不能用于 进程上下文 (会引起死锁) 。而 信号量不允许使用在中断中,而可以用于进程上下文  


3)、自旋锁保持期间是抢占失效的,自旋锁被持有时,内核不能被抢占,而 信号量和读写信号量保持期间是可以被抢占的(意味着可以被中断)




使用场所:


信号量主要适用于进程间通信,当然,也可用于线程间通信。


而互斥锁只能用于线程间通信。