并发机制的由来:
很多人会问这样的问题,Linux内核中提供了各式各样的锁机制到底有何作用?追根到底其实是由于操作系统中存在多进程对共享资源的并发访问,从而引起了进程间的竞态。这其中包括了我们所熟知的SMP系统,多核间的相互竞争资源,单CPU之间的相互竞争,中断和进程间的相互抢占等诸多问题。
原子概念:
所谓的原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断,也就是说,它的最小的执行单位,不能有比它更小的执行单元,因此这里的原子实际是使用了物理学里物质微粒的概念。
定义:
Linux提供了一组操作来保证对变量的原子操作。这些操作可用来避免简单的竞争条件。原子操作执行时不会被打断或干扰。在单处理器上,一旦启动原子操作,则从操作开始到结束的这段 时间内,不会中断线程。此外,在多处理器系统中,原子操作所针对的变量被锁定,以免被其他进程访问,直到原子操作结束。
具体实现:
原子操作主要用来实现资源计数,很多引用计数就是通过原子操作实现的。
typedef struct {int counter;}atomic_t;
该函数对原子类型的变量进行原子读操作,它返回原子类型的变量v的值。
(1)atomic_read(atomic_t *v)
该函数设置原子类型的变量v的值为i。
(2)atomic_set(atomic_t *v,int i);
该函数给原子类型变量v增加i。
(3)atomic_add(int i, atomic_t *v);
该函数给原子类型变量v减去i。
(4)atomic_sub(int i, atomic_t *v);
该函数从原子类型的变量v中减去i,并判断结果是否是0,如果为0,返回真,否则返回假。
(5)atomic_sub_and_test(int i, atomic_t *v);
该函数对原子变量v的增加1。
(6) atomic_inc(atomic_t *v);
该函数对原子变量v原子的减少1。
(7)atomic_dec(atomic_t *v);
该函数先测试后操作,先判断结果是否为0,如果是0,返回真,然后对原子变量v减少1.
(8)atomic_dec_and_test(atomic_t *v);
该函数先测试后操作,先判断结果是否为0,如果是0,返回真,然后对原子变量v增加1.
(9)atomic_inc_and_test(atomic_t *v);
该函数属于先操作后返回,对原子类型的变量v原子的增加i,并且返回指向新的的指针。
(10)atomic_add_return(int i, atomic_t *v);
该函数属于先操作后返回,对原子类型的变量v原子的减少i,并且返回指向新的的指针。
(11)atomic_sub_return(int i, atomic_t *v);
demo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/export.h> #include <linux/fs.h> #include <linux/mm.h> #include <linux/major.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/blkdev.h> #include <linux/completion.h> #include <linux/compat.h> #include <linux/chio.h> #include <linux/mutex.h> #include <linux/idr.h> #include <linux/slab.h> #include <linux/delay.h> #include <sound/core.h> #include <sound/control.h> #include <sound/pcm.h> #include <sound/ak4113.h> #include <sound/asoundef.h> #include <sound/info.h> /* oop编程的思想: 1.设计和分配结构体 2.设置 3.注册 */ //static 它的作用域只在本文件中 #define LKM_NAME "lkm_memory" #define LKM_MEM_SIZE 1024 //构造对象的结构体 struct lkm_memory_dev{ atomic_t open_count; unsigned char *lkm_mem_name; int lkm_mem_major; int lkm_mem_minor; struct file_operations *fops; struct class *lkm_mem_class; unsigned char *memory[LKM_MEM_SIZE]; //内存总空间 unsigned short len; //current mem len 当前内存长度 }; //建立全局结构体对象 static struct lkm_memory_dev *plkm_memory_dev; static int lkm_mem_open(struct inode * pinode, struct file * filep) { printk("lkm_memory_openn"); //如何进行LKM对象的注册,将每个设备的对象注册在属于该设备的文件私有数据域中 //为啥重要呢? filep->private_data=plkm_memory_dev; //根据原子变量的值做判断,当前设备是否已经被打开过 if(!atomic_dec_and_test(&plkm_memory_dev->open_count)) { printk("lkm_memory_busy"); atomic_inc(&plkm_memory_dev->open_count); return -EBUSY; } return 0; } //参数四 :位置 static ssize_t lkm_mem_read (struct file *filp, char __user *buf, size_t len, loff_t * pos) { unsigned long ptmp = *pos; unsigned int count = len; int iRet =0; printk("lkm_memory_readn"); //拿到LKM对象 struct lkm_memory_dev *dev = (struct lkm_memory_dev *)filp->private_data; if(ptmp == 0) { return 0; } if(count > ptmp) count=ptmp; //主要作用就是从内核空间拷贝一块儿数据到用户空间 if(copy_to_user(buf,dev->memory+ptmp,count)) { iRet = -EFAULT; } else { *pos -= count; iRet = count; printk("lkm_memory:read %u bytes from %lun",count,ptmp); } return iRet; } static ssize_t lkm_mem_write (struct file *filp, const char __user * buf, size_t len, loff_t * pos) { //读写指针自己动 unsigned long ptmp = *pos; unsigned int count = len; int iRet =0; printk("lkm_memory_writen"); //拿到LKM对象 struct lkm_memory_dev *dev = (struct lkm_memory_dev *)filp->private_data; if(ptmp >=LKM_MEM_SIZE) { return 0; } if(count >LKM_MEM_SIZE-ptmp) count=LKM_MEM_SIZE-ptmp; if(copy_from_user(dev->memory+ptmp,buf,count)) { iRet = -EFAULT; } else { *pos += count; iRet = count; printk("lkm_memory:written %u bytes from %lun",count,ptmp); } return iRet; } static int lkm_mem_release(struct inode *pinode, struct file *filep) { printk("lkm_memory_releasen"); //拿到设备结构体 struct lkm_memory_dev *dev = (struct lkm_memory_dev *)filep->private_data; filep->private_data = NULL; atomic_inc(&plkm_memory_dev->open_count); return 0; } //分配 static struct file_operations lkm_mem_fops={ .owner=THIS_MODULE, //指定当前模块 .open=lkm_mem_open, .release=lkm_mem_release, .read=lkm_mem_read, .write=lkm_mem_write, }; static int lkm_memory_setup_dev(struct lkm_memory_dev * dev,int index) { dev->lkm_mem_minor=index; memset(dev->memory,0,LKM_MEM_SIZE); dev->len=0; //创建lkm时,初始化当前打开计数为1 atomic_inc(&dev->open_count); return 1; } static __init int lkm_init(void) { int iRet; printk("SQ:module loadedn"); //为当前LKM对象分配内存 内存类型 //除了申请内核内存外,还会对申请到的内存内容清零。 plkm_memory_dev=kzalloc(sizeof(struct lkm_memory_dev), GFP_KERNEL); if(!plkm_memory_dev) { iRet=-ENOMEM; printk(KERN_ERR"lkm_memory:can't malloc memoryn"); goto error_alloc; } //对LKM进行设置 //对lkm_mem_name 分配一个内存 plkm_memory_dev->lkm_mem_name=kzalloc(sizeof(LKM_NAME), GFP_KERNEL); if( !plkm_memory_dev->lkm_mem_name) { iRet=-ENOMEM; printk(KERN_ERR"lkm_mem_name:can't malloc memoryn"); goto error_alloc_name; } //对name 赋值 memcpy(plkm_memory_dev->lkm_mem_name,LKM_NAME,sizeof(LKM_NAME)); plkm_memory_dev->fops=&lkm_mem_fops; plkm_memory_dev->lkm_mem_major= register_chrdev(0, plkm_memory_dev->lkm_mem_name,plkm_memory_dev->fops); if (plkm_memory_dev->lkm_mem_major< 0) { iRet=plkm_memory_dev->lkm_mem_major; printk(KERN_ERR"lkm_memory:can't register char devicen"); goto error_register; } //调用当前的LKM结构体综合设置函数 iRet=lkm_memory_setup_dev(plkm_memory_dev,0); if(!iRet) { iRet=-EINVAL; printk(KERN_ERR"lkm_memory:lkm_memory_setup_dev_errorn"); goto error_set_dev; } plkm_memory_dev->lkm_mem_class = class_create(THIS_MODULE, plkm_memory_dev->lkm_mem_name); if (IS_ERR(plkm_memory_dev->lkm_mem_class)) { iRet=PTR_ERR(plkm_memory_dev->lkm_mem_class); printk(KERN_ERR"lkm_memory:can't class_createn"); goto error_class_create; } //devt相当于num //主从设备号的合体 //主设备号对应一个类 //从设备号对应一个相应的设备 device_create(plkm_memory_dev->lkm_mem_class, NULL,MKDEV(plkm_memory_dev->lkm_mem_major,plkm_memory_dev->lkm_mem_minor), NULL,plkm_memory_dev->lkm_mem_name); return 0; error_class_create: error_set_dev: unregister_chrdev(plkm_memory_dev->lkm_mem_major,plkm_memory_dev->lkm_mem_name); error_register: kfree(plkm_memory_dev->lkm_mem_name); error_alloc_name: kfree(plkm_memory_dev); error_alloc: return iRet; } static __exit void lkm_exit(void) { printk("SQ:module removedn"); device_destroy(plkm_memory_dev->lkm_mem_class, MKDEV(plkm_memory_dev->lkm_mem_major,plkm_memory_dev->lkm_mem_minor)); class_destroy(plkm_memory_dev->lkm_mem_class); unregister_chrdev(plkm_memory_dev->lkm_mem_major, plkm_memory_dev->lkm_mem_name); kfree(plkm_memory_dev->lkm_mem_name); kfree(plkm_memory_dev); } module_init(lkm_init); module_exit(lkm_exit); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("SQ"); MODULE_DESCRIPTION("LKM OOP"); MODULE_VERSION("1.0");
测试:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #define LKM_MEM_SIZE 1024 int main(int argc , char *argv[]) { int fd; unsigned int len=0; unsigned char buf[LKM_MEM_SIZE]; fd =open("/dev/lkm_memory",O_RDWR); if(fd<0) { printf("can't openn"); } while(1) { len=write(fd,"hello world",sizeof("hello world")); read(fd,buf,len); printf("LKM-READ :%sn",buf); sleep(10); } return 0; }
结果:
最后
以上就是洁净紫菜最近收集整理的关于Linux内核并发机制----原子操作的全部内容,更多相关Linux内核并发机制----原子操作内容请搜索靠谱客的其他文章。
发表评论 取消回复