RK3568平台 并发与竞争控制机制总结
2023-12-22 06:18:39
一.并发与竞争机制总结
二.原子操作
“原子”是化学世界中不可再分的最小微粒,一切物质都由原子组成。在Linux 内核中的原子操作可以理解为“不可被拆分的操作”,就是不能被更高等级中断抢夺优先的操作。在C语言中可以使用以下代码对一个整形变量赋值。
原子操作测试demo:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/atomic.h>
#include <linux/errno.h>
static atomic64_t v = ATOMIC_INIT(1);//初始化原子类型变量v,并设置为1
static int open_test(struct inode *inode,struct file *file)
{
if(atomic64_read(&v) != 1){//读取原子类型变量v的值并判断是否等于1
return -EBUSY;
}
atomic64_set(&v,0);//将原子类型变量v的值设置为0
//printk("\nthis is open_test \n");
return 0;
}
static ssize_t read_test(struct file *file,char __user *ubuf,size_t len,loff_t *off)
{
int ret;
char kbuf[10] = "topeet";//定义char类型字符串变量kbuf
printk("\nthis is read_test \n");
ret = copy_to_user(ubuf,kbuf,strlen(kbuf));//使用copy_to_user接收用户空间传递的数据
if (ret != 0){
printk("copy_to_user is error \n");
}
printk("copy_to_user is ok \n");
return 0;
}
static char kbuf[10] = {0};//定义char类型字符串全局变量kbuf
static ssize_t write_test(struct file *file,const char __user *ubuf,size_t len,loff_t *off)
{
int ret;
ret = copy_from_user(kbuf,ubuf,len);//使用copy_from_user接收用户空间传递的数据
if (ret != 0){
printk("copy_from_user is error\n");
}
if(strcmp(kbuf,"topeet") == 0 ){//如果传递的kbuf是topeet就睡眠四秒钟
ssleep(4);
}
else if(strcmp(kbuf,"itop") == 0){//如果传递的kbuf是itop就睡眠两秒钟
ssleep(2);
}
printk("copy_from_user buf is %s \n",kbuf);
return 0;
}
static int release_test(struct inode *inode,struct file *file)
{
//printk("\nthis is release_test \n");
atomic64_set(&v,1);//将原子类型变量v的值赋1
return 0;
}
struct chrdev_test {
dev_t dev_num;//定义dev_t类型变量dev_num来表示设备号
int major,minor;//定义int类型的主设备号major和次设备号minor
struct cdev cdev_test;//定义struct cdev 类型结构体变量cdev_test,表示要注册的字符设备
struct class *class_test;//定于struct class *类型结构体变量class_test,表示要创建的类
};
struct chrdev_test dev1;//创建chrdev_test类型的
struct file_operations fops_test = {
.owner = THIS_MODULE,//将owner字段指向本模块,可以避免在模块的操作正在被使用时卸载该模块
.open = open_test,//将open字段指向open_test(...)函数
.read = read_test,//将read字段指向read_test(...)函数
.write = write_test,//将write字段指向write_test(...)函数
.release = release_test,//将release字段指向release_test(...)函数
};
static int __init atomic_init(void)
{
if(alloc_chrdev_region(&dev1.dev_num,0,1,"chrdev_name") < 0 ){//自动获取设备号,设备名chrdev_name
printk("alloc_chrdev_region is error \n");
}
printk("alloc_chrdev_region is ok \n");
dev1.major = MAJOR(dev1.dev_num);//使用MAJOR()函数获取主设备号
dev1.minor = MINOR(dev1.dev_num);//使用MINOR()函数获取次设备号
printk("major is %d,minor is %d\n",dev1.major,dev1.minor);
cdev_init(&dev1.cdev_test,&fops_test);//使用cdev_init()函数初始化cdev_test结构体,并链接到fops_test结构体
dev1.cdev_test.owner = THIS_MODULE;//将owner字段指向本模块,可以避免在模块的操作正在被使用时卸载该模块
cdev_add(&dev1.cdev_test,dev1.dev_num,1);//使用cdev_add()函数进行字符设备的添加
dev1.class_test = class_create(THIS_MODULE,"class_test");//使用class_create进行类的创建,类名称为class_test
device_create(dev1.class_test,0,dev1.dev_num,0,"device_test");//使用device_create进行设备的创建,设备名称为device_test
return 0;
}
static void __exit atomic_exit(void)
{
device_destroy(dev1.class_test,dev1.dev_num);//删除创建的设备
class_destroy(dev1.class_test);//删除创建的类
cdev_del(&dev1.cdev_test);//删除添加的字符设备cdev_test
unregister_chrdev_region(dev1.dev_num,1);//释放字符设备所申请的设备号
printk("module exit \n");
}
module_init(atomic_init);
module_exit(atomic_exit)
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("topeet");
?测试app:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int fd;//定义int类型的文件描述符
char str1[10] = {0};//定义读取缓冲区str1
fd = open(argv[1],O_RDWR);//调用open函数,打开输入的第一个参数文件,权限为可读可写
if(fd < 0 ){
printf("file open failed \n");
return -1;
}
/*如果第二个参数为topeet,条件成立,调用write函数,写入topeet*/
if (strcmp(argv[2],"topeet") == 0 ){
write(fd,"topeet",10);
}
/*如果第二个参数为itop,条件成立,调用write函数,写入itop*/
else if (strcmp(argv[2],"itop") == 0 ){
write(fd,"itop",10);
}
close(fd);
return 0;
}
三.自旋锁
自旋锁是为了保护共享资源提出的一种锁机制。自旋锁(spin lock)是一种非阻塞锁,也就是说,如果某线程需要获取锁,但该锁已经被其他线程占用时,该线程不会被挂起,而是在不断的消耗 CPU 的时间,不停的试图获取锁。为了让后面那个请求锁的线程“稍等一下”,我们需让它进行自旋,如果在自旋完成后前面锁定同步资源的线程已经释放了锁,那么该线程便不必阻塞,并且直接获取同步资源,从而避免切换线程的开销。
测试demo:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/spinlock.h>
static spinlock_t spinlock_test;//定义spinlock_t类型的自旋锁变量spinlock_test
static int flag = 1;//定义flag标准为,flag等于1表示设备没有被打开,等于0则证明设备已经被打开了
static int open_test(struct inode *inode,struct file *file)
{
//printk("\nthis is open_test \n");
spin_lock(&spinlock_test);//自旋锁加锁
if(flag != 1){//判断标志位flag的值是否等于1
spin_unlock(&spinlock_test);//自旋锁解锁
return -EBUSY;
}
flag = 0;//将标志位的值设置为0
spin_unlock(&spinlock_test);//自旋锁解锁
return 0;
}
static ssize_t read_test(struct file *file,char __user *ubuf,size_t len,loff_t *off)
{
int ret;
char kbuf[10] = "topeet";//定义char类型字符串变量kbuf
printk("\nthis is read_test \n");
ret = copy_to_user(ubuf,kbuf,strlen(kbuf));//使用copy_to_user接收用户空间传递的数据
if (ret != 0){
printk("copy_to_user is error \n");
}
printk("copy_to_user is ok \n");
return 0;
}
static char kbuf[10] = {0};//定义char类型字符串全局变量kbuf
static ssize_t write_test(struct file *file,const char __user *ubuf,size_t len,loff_t *off)
{
int ret;
ret = copy_from_user(kbuf,ubuf,len);//使用copy_from_user接收用户空间传递的数据
if (ret != 0){
printk("copy_from_user is error\n");
}
if(strcmp(kbuf,"topeet") == 0 ){//如果传递的kbuf是topeet就睡眠四秒钟
ssleep(4);
}
else if(strcmp(kbuf,"itop") == 0){//如果传递的kbuf是itop就睡眠两秒钟
ssleep(2);
}
printk("copy_from_user buf is %s \n",kbuf);
return 0;
}
static int release_test(struct inode *inode,struct file *file)
{
printk("\nthis is release_test \n");
spin_lock(&spinlock_test);//自旋锁加锁
flag = 1;
spin_unlock(&spinlock_test);//自旋锁解锁
return 0;
}
struct chrdev_test {
dev_t dev_num;//定义dev_t类型变量dev_num来表示设备号
int major,minor;//定义int类型的主设备号major和次设备号minor
struct cdev cdev_test;//定义struct cdev 类型结构体变量cdev_test,表示要注册的字符设备
struct class *class_test;//定于struct class *类型结构体变量class_test,表示要创建的类
};
struct chrdev_test dev1;//创建chrdev_test类型的
struct file_operations fops_test = {
.owner = THIS_MODULE,//将owner字段指向本模块,可以避免在模块的操作正在被使用时卸载该模块
.open = open_test,//将open字段指向open_test(...)函数
.read = read_test,//将read字段指向read_test(...)函数
.write = write_test,//将write字段指向write_test(...)函数
.release = release_test,//将release字段指向release_test(...)函数
};
static int __init atomic_init(void)
{
spin_lock_init(&spinlock_test);
if(alloc_chrdev_region(&dev1.dev_num,0,1,"chrdev_name") < 0 ){//自动获取设备号,设备名chrdev_name
printk("alloc_chrdev_region is error \n");
}
printk("alloc_chrdev_region is ok \n");
dev1.major = MAJOR(dev1.dev_num);//使用MAJOR()函数获取主设备号
dev1.minor = MINOR(dev1.dev_num);//使用MINOR()函数获取次设备号
printk("major is %d,minor is %d\n",dev1.major,dev1.minor);
cdev_init(&dev1.cdev_test,&fops_test);//使用cdev_init()函数初始化cdev_test结构体,并链接到fops_test结构体
dev1.cdev_test.owner = THIS_MODULE;//将owner字段指向本模块,可以避免在模块的操作正在被使用时卸载该模块
cdev_add(&dev1.cdev_test,dev1.dev_num,1);//使用cdev_add()函数进行字符设备的添加
dev1.class_test = class_create(THIS_MODULE,"class_test");//使用class_create进行类的创建,类名称为class_test
device_create(dev1.class_test,0,dev1.dev_num,0,"device_test");//使用device_create进行设备的创建,设备名称为device_test
return 0;
}
static void __exit atomic_exit(void)
{
device_destroy(dev1.class_test,dev1.dev_num);//删除创建的设备
class_destroy(dev1.class_test);//删除创建的类
cdev_del(&dev1.cdev_test);//删除添加的字符设备cdev_test
unregister_chrdev_region(dev1.dev_num,1);//释放字符设备所申请的设备号
printk("module exit \n");
}
module_init(atomic_init);
module_exit(atomic_exit)
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("topeet");
?测试app:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int fd;//定义int类型的文件描述符
char str1[10] = {0};//定义读取缓冲区str1
fd = open(argv[1],O_RDWR);//调用open函数,打开输入的第一个参数文件,权限为可读可写
if(fd < 0 ){
printf("file open failed \n");
return -1;
}
/*如果第二个参数为topeet,条件成立,调用write函数,写入topeet*/
if (strcmp(argv[2],"topeet") == 0 ){
write(fd,"topeet",10);
}
/*如果第二个参数为itop,条件成立,调用write函数,写入itop*/
else if (strcmp(argv[2],"itop") == 0 ){
write(fd,"itop",10);
}
close(fd);
return 0;
}
?四.互斥锁
待更新。。。。。。
文章来源:https://blog.csdn.net/weixin_49303682/article/details/135142400
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!