现在的位置: 首页 > 综合 > 正文

Linux 内核同步机制——互斥锁(转)

2013年10月09日 ⁄ 综合 ⁄ 共 3559字 ⁄ 字号 评论关闭

互斥锁非常简单,不过有一些规则必须牢记。同一时间只能有一个任务持有互斥锁,而且只有这个任务能对互斥锁进行 解锁。互斥锁不能进行递归锁定或解锁,并且互斥锁可能不能用于交互上下文。不过互斥锁比当前的内核信号量选项更快,并且更加紧凑.
互斥锁在Linux操作系统的数据结构struct mutex形式如下:
/*
* Simple, straightforward mutexes with strict semantics:
*
* - only one task can hold the mutex at a time
* - only the owner can unlock the mutex
* - multiple unlocks are not permitted
* - recursive locking is not permitted
* - a mutex object must be initialized via the API
* - a mutex object must not be initialized via memset or copying
* - task may not exit with mutex held
* - memory areas where held locks reside must not be freed
* - held mutexes must not be reinitialized
* - mutexes may not be used in hardware or software interrupt
*   contexts such as tasklets and timers
*
* These semantics are fully enforced when DEBUG_MUTEXES is
* enabled. Furthermore, besides enforcing the above rules, the mutex
* debugging code also implements a number of additional features
* that make lock debugging easier and faster:
*
* - uses symbolic names of mutexes, whenever they are printed in debug output
* - point-of-acquire tracking, symbolic lookup of function names
* - list of all locks held in the system, printout of them
* - owner tracking
* - detects self-recursing locks and prints out all relevant info
* - detects multi-task circular deadlocks and prints out all affected
*   locks and tasks (and only those tasks)
*/

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
};
在系统通过宏DEFINE_MUTEX定义一个互斥锁并且完成初始化:
#define DEFINE_MUTEX(mutexname) \
struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
                                         |
                                         |
                                         #define __MUTEX_INITIALIZER(lockname) \
   { .count = ATOMIC_INIT(1) \
   , .wait_lock = __SPIN_LOCK_UNLOCKED(lockname.wait_lock) \
   , .wait_list = LIST_HEAD_INIT(lockname.wait_list) \
   __DEBUG_MUTEX_INITIALIZER(lockname) \
   __DEP_MAP_MUTEX_INITIALIZER(lockname) }
对互斥锁的操作,Linux OS提供了一些API对互斥锁的操作:
第一个API:void inline __sched mutex_lock(struct mutex *lock)给互斥锁加锁
用mutex_lock()锁住lock指向的互斥锁。如果mutex已经被锁,当前调用线程阻塞直到互斥锁被其他线程释放(阻塞线程按照线程优先级等待)。当mutex_lock()返回,说明互斥锁已经被当前线程成功加锁。
返回值--mutex_lock()在成功执行后返回零。其他值意味着错误。在以下情况发生时,函数失败并返回相关值。
EINVAL 非法参数
EFAULT mp指向一个非法地址。

第二个API:int __sched mutex_trylock(struct mutex *lock)非阻塞的方式为互斥锁加锁
用mutex_trylock()来尝试给lock指向的互斥锁加锁。这个函数是mutex_lock()的非阻塞版本。当一个互斥锁已经被锁,本调用返回错误。否则,互斥锁被调用者加锁。
返回值--mutex_trylock()在成功执行后返回零。其他值意味着错误。在以下情况发生时,函数失败并返回相关值。
EINVAL 非法参数
EFAULT mp指向一个非法地址。

第三个API:void __sched mutex_unlock(struct mutex *lock)给互斥锁解锁
用mutex_unlock()给由lock指向的互斥锁解锁。互斥锁必须处于加锁状态且调用本函数的线程必须是给互斥锁加锁的线程。如果有其他线程在等待互斥锁,在等待队列头上的线程获得互斥锁并脱离阻塞状态。
返回值--mutex_unlock()在成功执行后返回零。其他值意味着错误。在以下情况发生时,函数失败并返回相关值。
EINVAL 非法参数
EFAULT mp指向一个非法地址。

第四个API:void mutex_destroy(struct mutex *lock)清除互斥锁,使互斥锁不可用
用mutex_destroy()函数解除由lock指向的互斥锁的任何状态。在调用执行这个函数的时候,lock指向的互斥锁不能在被锁状态。储存互斥锁的内存不被释放。
返回值--mutex_destroy()在成功执行后返回零。其他值意味着错误。在以下情况发生时,函数失败并返回相关值。
EINVAL 非法参数
EFAULT mp指向一个非法地址。

第五个API:static inline int mutex_is_locked(struct mutex *lock)测试互斥锁的状态
这个调用实际上编译成一个内联函数。如果互斥锁被持有(锁定),那么就会返回 1;否则,返回 0。 

实际使用过程自己用了一下,效果还是不错的;‘

static struct mutex sensor_mutex;   //声明一下
void __sched sensor_mutex_lock(struct mutex *lock)
{
    mutex_lock(lock);
   
    APS_DBG("psensor_mutex_lock is called\n");
    
    
}
void __sched sensor_mutex_unlock(struct mutex *lock)
{
    mutex_unlock(lock);
    
    APS_DBG("psensor_mutex_unlock is called\n");
    
}

这两个是在code中添加的加锁与解锁的code;

使用方法就是在我想加锁的地方上面加个锁,之后一定要记得解锁;

    	sensor_mutex_lock(&sensor_mutex); //加锁
	buffer[0]=0x02;
	res = i2c_master_send(client, buffer, 0x1);
	if(res <= 0)
	{
		goto EXIT_ERR;
	}
 sensor_mutex_unlock(&sensor_mutex); //解锁


我在i2c这里面加锁的原因是我有发现linux可能在传输I2C 数据的时候,可能不够完整,

所以要给发送过程加个锁, 确保其发送数据为我想发送的数据;

 

抱歉!评论已关闭.