因为是从有道笔记复制过来的,好多图片复制不过来,不知道怎么搞,希望有大佬能指点一下
帖子:https://blog.csdn.net/shaohua_lv/article/details/70257100
信号量 与 互斥量(锁)
一、概念和定义(作用?)
信号量:多线程同步使用的;一个线程完成某个动作后通过信号告诉别的线程,别的线程才可以执行某些动作;
互斥量:多线程互斥使用的;一个线程占用某个资源,那么别的线程就无法访问,直到该线程离开,其他线程才可以访问该资源;
他们主要是目的不同而已,操作基本相同
二、信号量 与 互斥量的区别
1、互斥量用于线程的互斥,信号量用于线程的同步:
互斥:指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排他性。但是互斥无法限制访问者对资源的访问顺序,所以访问是无序的;(只告诉其他进程,什么时候可以访问,没有规定他们的访问顺序)
同步:指在互斥的基础上(多数情况),通过其他机制实现访问者对资源的有序访问。大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况指可以允许多个访问者同时访问资源。(不只告诉其他进程什么时候可以访问,还规定各进程的访问顺序)
2、互斥量值只能是0/1,信号量值可以为非负整数:
一个互斥量只能用于一个资源的互斥访问,不能实现多个资源的多线程互斥问题;
一个信号量可以实现多个同类资源的多线程互斥和同步。当信号量为单值信号量时,也可以完成一个资源的互斥访问;
3、互斥量的加锁和解锁必须由同一线程分别对应使用(表明这个进程在用,或者这个进程结束使用);而信号量可以由一个线程释放,另外一个线程得到。
三、信号量与互斥量的详细分析
信号量--Semaphore:
分类:
二进制信号量(Binary Semaphore):只允许信号量取0或1值,其同时只能被一个线程获取;
整型信号量(Integer Semaphore):信号量取值是整数,可被多个线程同时获得,直到信号量的值变为0;
记录型信号量(Record Semaphore):每个信号量s除以一个整数值value(计数)外,还有一个等待队列List,其中是阻塞在该信号量的各个线程的标识。
当信号量被释放1个,值被加1后,系统自动从等待队列中唤醒一个等待中的线程;让其获得信号量,同时信号量再减1。
Semaphore 抽象操作:
创建create() /等待 wait() / 释放 post() /试图等待 trywait() / 销毁 destroy()
互斥量--Mutex:
互斥量表现互斥现象的数据结构,常用作保护从中断来的临界段代码并且在共享同步使用的资源;
Mutex本质就是一把锁,提供对资源的独占式访问,所以Mutex主要的作用是互斥。
Mutex 可抽象为4个操作:
- 创建 Create
- 加锁 Lock
- 解锁 Unlock
- 销毁 Destroy
四、信号量与互斥量,原子变量表现
互斥量:在同时开两个应用进程时,有一个接收不到数据,读取不到数据,只有等前面的应用关掉后才可以
信号量:同时打开两个进程时,有一个接收不到数据,读取不到数据,只有等前面的应用关掉后才可以
原子变量:不能同时打开两个应用进程,后面的会提示打不开
五、互斥量
1. 初始化互斥体 -- mutex_init();
2. 获得互斥体 -- mutex_lock();
3. 释放互斥体 -- mutex_unlock();
mutex不能使用在 中断的上下文 中。
1. mutex_init(), 注意mutex使用之前都需要先init
2. mutex_lock(), 注意看注释说明,
a. 如果mutex已经被其他task获取,那么目前的task先sleep直到获取;
b. mutex不能被嵌套获取;上一个task释放mutex之后,才能被其他的task获取;
c. mutex要先被初始化才能使用;mutex正在使用过程中,其内存不能被释放;
3. mutex_unlock(), 释放互斥体
a. 释放之前获得的mutex;
b. mutex只有被获得,才能调用这个函数来释放;换言之,如果没有获得,就没有必要做释放的动作;
程序分析
---------------------------mutex.c-------------------------------------------------------------------
#include <linux/module.h>
2 #include <linux/init.h>
3 #include <linux/major.h>
4 #include <linux/cdev.h>
5 #include <linux/device.h>
6 #include <linux/types.h>
7 #include <linux/fs.h>
8 #include <asm/uaccess.h>
9 #include <linux/io.h>
10 #include <linux/sched.h>
11 //#include <asm/irq.h>
12 #include <linux/gpio.h>
13 #include <linux/interrupt.h>
14 #include <linux/poll.h>
15
16 #define TAG "semap "
17 #define INT_GPIO 91
18
19 static int key_major;
20 static struct cdev key_cdev;
21 static struct class *key_class;
22 volatile unsigned long *tlmm_gpio_cfg;
23 volatile unsigned long *tlmm_in_out;
24 static int key_press = 0;
25 static int key_value = 0;
26 static int irq;
27
28 static wait_queue_head_t kwait;
29
30 static struct mutex kmutex; //定义互斥结构体
31
32 static irqreturn_t key_irq_thread(int irq, void *data)
33 {
34 int value;
35
36 printk(TAG" func:%s line:%d\n", __func__, __LINE__);
37 value = *tlmm_in_out;
38 value &= 0x1;
39 if (value ) {
40 key_value = 0;
41 } else {
42 key_value = 1;
43 }
44 wake_up_interruptible(&kwait);
45 key_press = 1;
46
47 return IRQ_HANDLED;
48 }
49 static ssize_t key_read(struct file *file, char __user *buffer,
50 size_t count, loff_t *ppos)
51 {
52 if(count != 1 )
53 return -EINVAL;
54
55 if((file->f_flags & O_NONBLOCK) && !key_press)
56 return -EAGAIN;
57
58 printk(TAG" func:%s line:%d\n", __func__, __LINE__);
59 if (!key_press) {
60 wait_event_interruptible(kwait, key_press);
61 }
62 if(key_press) {
63 if(!copy_to_user(buffer, &key_value, 1)) {
64 printk(TAG"%s key is press\n", __func__);
65 key_press = 0;
66 } else {
67 printk(TAG"%s copy to user error\n", __func__);
68 return -EFAULT;
69 }
70 }
71
72 return count;
73 }
74
75 ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
76 {
77 printk(TAG" func:%s line:%d\n", __func__, __LINE__);
78
79 return count;
80 }
81
82 static int key_open(struct inode *inode, struct file *file)
83 {
84 int ret = 0;
85
86 printk(TAG" func:%s line:%d\n", __func__, __LINE__);
87 mutex_lock(&kmutex); //获得互斥体
88
89 return ret;
90 }
91
92 static unsigned int key_poll(struct file *file, poll_table *wait)
93 {
94 unsigned int mask;
95
96 printk(TAG" func:%s line:%d\n", __func__, __LINE__);
97 poll_wait(file, &kwait, wait);
98 if (key_press) {
99 mask |= POLLIN | POLLRDNORM;
100 }
101
102 return mask;
103 }
104
105 static int key_release(struct inode *inode, struct file *file)
106 {
107 mutex_unlock(&kmutex); //释放互斥体
108 printk(TAG" func:%s line:%d\n", __func__, __LINE__);
109
110 return 0;
111 }
112
113 static const struct file_operations key_ops = {
114 .owner = THIS_MODULE,
115 .read = key_read,
116 .write = key_write,
117 .open = key_open,
118 .poll = key_poll,
119 .release = key_release,
120 };
121
122 static int my_key_init(void)
123 {
124 int retval;
125 dev_t dev_id;
126
127 printk(TAG" func:%s line:%d\n", __func__, __LINE__);
128 retval = alloc_chrdev_region(&dev_id, 0, 1, "semap"); //0,1
129 key_major = MAJOR(dev_id);
130 printk(TAG"major is %d\n", key_major);
131 if (retval < 0) {
132 printk(TAG"can't get major number\n");
133 goto error;
134 }
135
136 cdev_init(&key_cdev, &key_ops);
137 retval = cdev_add(&key_cdev, dev_id, 1); //1
138 if (retval < 0) {
139 printk(TAG"cannot add cdev\n");
140 goto cleanup_alloc_chrdev_region;
141 }
142
143 key_class = class_create(THIS_MODULE, "semap");
144 if (IS_ERR(key_class)) {
145 printk(TAG "Error creating key class.\n");
146 cdev_del(&key_cdev);
147 retval = PTR_ERR(key_class);
148 goto cleanup_alloc_chrdev_region;
149 }
150
151 device_create(key_class, NULL, MKDEV(key_major, 0), NULL, "semap");
152
153 tlmm_gpio_cfg = (volatile unsigned long *)ioremap(0x105B000, 8);
154 tlmm_in_out = tlmm_gpio_cfg + 1;
155 *tlmm_gpio_cfg |= 0x3;
156
157 init_waitqueue_head(&kwait);
158
159 irq = gpio_to_irq(INT_GPIO);
160 printk(TAG"%s irq is %d\n", __func__, irq);
161 retval = request_threaded_irq(irq, NULL, key_irq_thread, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "vol_ key", NULL);
162 printk(TAG"%s ret is %d\n", __func__, retval);
163
164 mutex_init(&kmutex); //初始化互斥体
165
166 return 0;
167
168 cleanup_alloc_chrdev_region:
169 unregister_chrdev_region(dev_id, 0);
170 error:
171 return retval;
172 }
173
174 static void key_exit(void)
175 {
176 dev_t dev_id = MKDEV(key_major, 0);
177
178 free_irq(irq, NULL);
179 iounmap(tlmm_gpio_cfg);
180 device_destroy(key_class, MKDEV(key_major, 0));
181 class_destroy(key_class);
182 cdev_del(&key_cdev);
183 unregister_chrdev_region(dev_id, 0);
184 printk(TAG" func:%s line:%d\n", __func__, __LINE__);
185 }
186
187 module_init(my_key_init);
188 module_exit(key_exit);
189 MODULE_LICENSE("GPL");
六、信号量
信号的初始化:
方法1 (静态法) :DEFINE_SEMAPHORE(key_sem); //在新的内核中直接用semaphore
此时信号量值被初始化为1 ,即互斥量。效果等同于DECLARE MUTEX(name);
具体函数情况如下:
#define DEFINE SEMAPHORE(name) \
struct semaphore name =-SEMAPHORE INITIALIZER(name, 1)//此处信号量结构体没有定义为指针,
#define SEMAPHORE INITIALIZER(name, n){ 、
lock=_SPIN LOCK_UNLOCKED((name).lock),
.count=n.
.wait list= LIST _HEAD INIT((name).wait_list),
方法2 (动态法) :struct semaphore sem;
void sema_ init(&sem,val);val为初始化信号量的值
获取信号最:void down(struct semaphore *name);
int down interruptible(struct semaphore *name)://操作被中断返回非0值
int down_trylock(struct semaphore *name)://若不可获得则返回0
建议使用interruptible版本,其中down_trylock版本不会导致休眠,一般在非阻塞进程中使用。
程放信号量:void up(struct semaphore *name);
信号的初始化
获取信号最:void down(struct semaphore *name);
程放信号量:void up(struct semaphore *name);
七、原子变量 (帖子https://blog.csdn.net/yikai2009/article/details/8650221)
所谓原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断,也就说,它的最小的执行单位,不可能有比它更小的执行单位。因此这里的原子实际是使用了物理学里的物质微粒的概念,所以它不允许两个应用进程同时打开它
1、定义原子变量,初始化为 1 :
2,在 open 函数里检测原子变量值:
如果没有进程在使用该驱动 ,原子变量值 为 1 。如果有进程打开驱动open,将原子变量减 一 为 0 ,函数返回 true ,
这样打开了、并使用该驱动, 原子变量变为 0;
如果再有进程来打开驱动程序,0-1 = 负1,返回 false ,else条件成立,运行里面的代码,提示不能打开,并将原子变量加一恢复到 0,程序返回;
3、在退出时 release函数 恢复原子变量值:
最后, 在应用程序退出时 release 函数, 自增 恢复原子变量值为 1: