互斥量、信号量、原子变量

因为是从有道笔记复制过来的,好多图片复制不过来,不知道怎么搞,希望有大佬能指点一下

 帖子: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:

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

简书-乡村码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值