kernel互斥锁mutex

互斥锁主要用于实现内核中的互斥访问功能。内核互斥锁是在原子 API 之上实现的,但这对于内核用户是不可见的。对它的访问必须遵循一些规则:同一时间只能有一个任务持有互斥锁,而且只有这个任务可以对互斥锁进行解锁。互斥锁不能进行递归锁定或解锁。一个互斥锁对象必须通过其API初始化,一个任务在持有互斥锁的时候是不能结束的,互斥锁所使用的内存区域是不能被释放的,使用中的互斥锁是不能被重新初始化的,并且互斥锁不能用于中断上下文。互斥锁比内核信号量更快,并且更加紧凑,因此如果它们满足您的需求,那么它们将是您明智的选择。

/linux/include/linux/mutex.h

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
  };

count指示互斥锁的状态:

     1 没有上锁,可以获得
     0 被锁定,不能获得
     负数 被锁定,且可能在该锁上有等待进程,初始化为没有上锁。

wait_lock等待获取互斥锁时使用的自旋锁。在获取互斥锁的过程中,操作会在自旋锁的保护中进行。初始化为为锁定。

wait_list等待互斥锁的进程队列。


相关API:

1、定义并初始化:

struct mutex mutex;

mutex_init(&mutex);

2、获取互斥锁:

(1)具体参见linux/kernel/mutex.c

void inline fastcall __sched mutex_lock(struct mutex *lock);
首先取得count的值,在将count置-1,判断如果原来count的置为1,也即互斥锁可以获得,则直接获取然后跳出。否则进入循环反复测试互斥锁的状态。在循环中,同样先取得互斥锁原来的状态,在将其-1,如果可以获取(等于1),则退出循环,否则设置当前进程的状态为不可中断状态,解锁自身的自旋锁,进入睡眠状态,待被再调度唤醒时,再获得自身的自旋锁,进入新一次的查询其自身状态(该互斥锁的状态)的循环。


(2)具体参见linux/kernel/mutex.c

int fastcall __sched mutex_lock_interruptible(struct mutex *lock);

和mutex_lock()一样,在获得了互斥锁后会返回0。如果在等待获取锁的时候进入睡眠状态并收到一个信号(被信号打断睡眠),则返回-EINIR。


(3)具体参见linux/kernel/mutex.c

int fastcall __sched mutex_trylock(struct mutex *lock);

试图获取互斥锁,如果成功获取则返回1,否则返回0,不等待。


3、释放互斥锁:

具体参见linux/kernel/mutex.c

void fastcall mutex_unlock(struct mutex *lock);

释放被当前进程获取的互斥锁。该函数不能用在中断上下文中,而且不允许去释放一个没有上锁的互斥锁。

内核线程是在Linux内核层面运行的线程,它们与用户空间的线程有所不同。在内核中,我们可以使用互斥锁进行多个内核线程之间的同步。 下面是一个简单的内核模块示例,它创建了两个内核线程,这两个线程会轮流访问一个共享的计数器,并使用互斥锁进行同步: ```c #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/kthread.h> #include <linux/mutex.h> static struct task_struct *thread1, *thread2; static int counter = 0; static DEFINE_MUTEX(mutex); int thread_func(void *data) { int i; for (i = 0; i < 5; i++) { mutex_lock(&mutex); counter++; printk(KERN_INFO "Counter incremented by %d\n", counter); mutex_unlock(&mutex); msleep(1000); } return 0; } static int __init my_module_init(void) { mutex_init(&mutex); thread1 = kthread_create(thread_func, NULL, "my_thread1"); if (IS_ERR(thread1)) { printk(KERN_INFO "Failed to create thread1\n"); return PTR_ERR(thread1); } wake_up_process(thread1); thread2 = kthread_create(thread_func, NULL, "my_thread2"); if (IS_ERR(thread2)) { printk(KERN_INFO "Failed to create thread2\n"); kthread_stop(thread1); return PTR_ERR(thread2); } wake_up_process(thread2); return 0; } static void __exit my_module_exit(void) { kthread_stop(thread1); kthread_stop(thread2); mutex_destroy(&mutex); } module_init(my_module_init); module_exit(my_module_exit); ``` 在上面的代码中,我们首先定义了一个共享的计数器`counter`,然后创建了两个内核线程`thread1`和`thread2`,这两个线程会轮流访问计数器,并使用互斥锁`mutex`进行同步。 在线程函数`thread_func`中,我们使用`mutex_lock`函数对互斥锁进行加锁操作,然后对计数器进行加1操作,并打印出新的计数器值。在操作完成后,我们使用`mutex_unlock`函数对互斥锁进行解锁操作。这样可以保证在任何时刻,只有一个线程可以访问计数器。 在模块的初始化函数`my_module_init`中,我们首先使用`mutex_init`函数对互斥锁进行初始化。然后创建两个内核线程,并使用`wake_up_process`函数启动它们。在模块的退出函数`my_module_exit`中,我们使用`kthread_stop`函数停止内核线程,并使用`mutex_destroy`函数销毁互斥锁。 需要注意的是,在内核中,我们可以使用`mutex_lock`和`mutex_unlock`函数对内核互斥锁进行加锁和解锁操作,这些函数与用户空间的`pthread_mutex_lock`和`pthread_mutex_unlock`函数使用方法类似,但是函数名略有不同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值