在Linux线程同步机制里常用有互斥锁和信号量两种方法.
在理解为什么有些代码需要加锁后再执行,先了解一下原子操作的概念
所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束, 中间不会有任何 context switch (切换到另一个线程) 原子操作是不可分割的,在执行完毕之前不会被任何其它任务或事件中断 ——百度百科
意思就是这种操作是单位级的操作,执行过程保证绝对不受影响,执行结果一定 .而且互斥锁必须总是由它上锁的线程解锁。
RTDM还有一种锁叫自旋锁(Spinlock),它和互斥锁的区别是:
自旋锁是一种互斥锁的实现方式,相比一般的互斥锁会在等待期间放弃cpu,自旋锁则是不断循环并测试锁的状态,这样就一直占着cpu。自旋锁:与互斥量类似,它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙等(自旋)阻塞状态。用在以下情况:锁持有的时间短,而且线程并不希望在重新调度上花太多的成本。"原地打转"(自旋)。
xenomai RTDM 模式下的互斥锁有关函数
//释放互斥锁
void rtdm_mutex_unlock ( rtdm_mutex_t * mutex )
参数mutex是rtdm_mutex_init()返回的互斥句柄
这个函数释放给定的互斥锁,唤醒可能被rtdm_mutex_lock()或rtdm_mutex_timedlock()阻塞的等待者。
//请求带超时的互斥锁
int rtdm_mutex_timedlock ( rtdm_mutex_t * mutex,
nanosecs_rel_t timeout,
rtdm_toseq_t * timeout_seq
)
参数:
mutex , 是rtdm_mutex_init()返回的互斥句柄
timeout ,相对超时时间单位纳秒,参考 RTDM_TIMEOUT_xxx 具体的数值
timeout_seq, 由rtdm_toseq_init()或NULL返回的超时序列的句柄
返回值:
成功请求返回0,其他值如下
-ETIMEDOUT ,如果在指定的时间内没有满足请求。
-EWOULDBLOCK ,如果timeout为负,而信号量值当前不是正的。
-EIDRM ,如果互斥对象已被销毁。
-EPERM ,如果检测到非法调用环境。
详细超时的值
RTDM_TIMEOUT_INFINITE 永远阻塞
RTDM_TIMEOUT_NONE 任何负超时都意味着无阻塞。
//动态初始化锁,该函数对任务没有实时性限制,它申请的是一个自旋锁
static void rtdm_lock_init( rtdm_lock_t * lock )
//从不可抢占的上下文获取锁
static void rtdm_lock_get( rtdm_lock_t *lock )
//释放锁而不进行抢占恢复
static void rtdm_lock_put( rtdm_lock_t * lock )
//释放锁并恢复抢占状态
static void rtdm_lock_put_irqrestore(rtdm_lock_t *lock,rtdm_lockctx_t context)
//获取锁定和禁用抢占,通过停止头域
((__context) = __rtdm_lock_get_irqsave(__lock))
xenomai RTDM 模式下的信号量有关函数
rtdm_sem_init(rtdm_sem_t * sem,unsigned long value ) //信号量初始化,值为value
int rtdm_sem_down (rtdm_sem_t *sem) //信号量自减
int rtdm_sem_up (rtdm_sem_t *sem) //信号量增加
在rtdm设备中,rtdm_driver的device_flags若设置了独占模式保护了内核资源的安全性,但这样该模块则只能被一个应用打开,限制了其并发使用,要解决这个问题就需要采用锁机制来保证既能多个应用使用.
/* * Copyright (C) 2020 BNIS. * */ #include <linux/module.h> #include <rtdm/driver.h> #include <rtdm/testing.h> MODULE_DESCRIPTION("RTDM Mutext test"); MODULE_AUTHOR("bniss@aliyun.com"); MODULE_VERSION("0.1.0"); MODULE_LICENSE("GPL"); struct rtdm_basic_context { int buffer_data; }; rtdm_lock_t lock; rtdm_sem_t sem; int open_times = 0;//统计总打开的次数 int inUse_times = 0;//当前还在是使用的次数 static int rtdm_basic_open(struct rtdm_fd *fd, int oflags) { struct rtdm_basic_context *ctx = rtdm_fd_to_private(fd); //打开的设备名: /dev/rtdm1 rtdm_lock_get(&lock); rtdm_task_sleep(300000000ULL);//sleep 300ms test open_times++; inUse_times++; printk("device is open , flag = %d ,open/inUse = %d/%d ", oflags,open_times,inUse_times); rtdm_lock_put(&lock); return 0; } static void rtdm_basic_close(struct rtdm_fd *fd) { rtdm_lock_get(&lock); inUse_times--; printk("device is close. in use times = %d " , inUse_times ); rtdm_lock_put(&lock); } static int rtdm_basic_ioctl_rt(struct rtdm_fd *fd, unsigned int request, void __user *arg) { rtdm_sem_down(&sem); int ret = 0 ; int *ext = (int*)arg; printk(" RealTime Request = %d ! task id = %d ." , request,*ext); switch (request) { case 0x001: printk(" RT Request case = 1 ."); break; case 0x002: printk(" RT Request case = 2. "); ret = -EFAULT; break; case 0x003: printk(" RT Request case = 3. "); rtdm_task_sleep(500000ULL); break; default: printk(" RT Request other_case = %d. ", request ); ret = -ENOSYS; break; } rtdm_sem_up(&sem); return ret; } static int rtdm_basic_ioctl_nrt(struct rtdm_fd *fd, unsigned int request, void __user *arg) { rtdm_sem_down(&sem); struct rtdm_basic_context *ctx = rtdm_fd_to_private(fd); int* ext =(int*)arg; int ret = 0 ; printk(" No-RealTime Request = %d ! task id = %d ." , request ,*ext); switch (request) { case 0x001: printk(" nRT Request case = 1 ."); break; case 0x002: printk(" nRT Request case = 2. "); ret = -EFAULT; break; case 0x003: printk(" nRT Request case = 3. "); break; default: printk(" nRT Request other_case = %d. ", request ); ret = -ENOSYS; } rtdm_sem_up(&sem); return ret; } static struct rtdm_driver rtdm_basic_driver = { .profile_info = RTDM_PROFILE_INFO(rtdm_test_basic, RTDM_CLASS_TESTING, RTDM_SUBCLASS_RTDMTEST, RTTST_PROFILE_VER), .device_flags = RTDM_NAMED_DEVICE ,// 非独占| RTDM_EXCLUSIVE, .device_count = 2, .context_size = sizeof(struct rtdm_basic_context), .ops = { .open = rtdm_basic_open, .close = rtdm_basic_close, .ioctl_rt = rtdm_basic_ioctl_rt, .ioctl_nrt = rtdm_basic_ioctl_nrt, }, }; static struct rtdm_device device[2] = { [0 ... 1] = { .driver = &rtdm_basic_driver, .label = "rtdm%d", } }; static int __init rtdm_test_init(void) { int i, ret; printk("------rtdm initial--------- "); if (!realtime_core_enabled()) return -ENODEV; for (i = 0; i < ARRAY_SIZE(device); i++) { ret = rtdm_dev_register(device + i); if (ret) goto fail; } rtdm_lock_init(&lock); //初始化自旋锁 rtdm_sem_init(&sem,1);//信号量初始化 return 0; fail: printk("------ init fail:%d -------- ",ret); while (i-- > 0) rtdm_dev_unregister(device + i); return ret; } static void __exit rtdm_test_exit(void) { int i; printk("------rtdm exit--------- "); for (i = 0; i < ARRAY_SIZE(device); i++) rtdm_dev_unregister(device + i); rtdm_sem_destroy(&sem); } module_init(rtdm_test_init); module_exit(rtdm_test_exit);
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <rtdm/rtdm.h> #include <errno.h> #include <sys/resource.h> #include <unistd.h> #include <native/task.h> #define DEVICE_NAME "rtdm1" #define MAX_PRIO 99 RT_TASK task_desc1; RT_TASK task_desc2; RT_TASK task_desc3; typedef struct _TAG_TASK_DATA { int taskId; } TASK_DATA; void task_body (void *cookie){ TASK_DATA* taskDat =(TASK_DATA*) cookie; int tid = 0; if(taskDat){ tid = taskDat->taskId; } int i,ret,device; rt_printf(" task_body process ,task_id = %d \n",tid); /* open the device */ device = rt_dev_open(DEVICE_NAME, 0); if (device < 0) { rt_printf("ERROR : can't open device %s (%s)\n", DEVICE_NAME, strerror(-device)); return ; } else{ rt_printf("device open sucess ! \n"); } for(i=1;i<5;i++){ ret = rt_dev_ioctl (device, i, &tid ); rt_printf("user-request = %d , return = %d , taskId=%d \n", i, ret,tid ); rt_task_sleep(100000000ULL);//100ms } } int main(int argc, char *argv) { int ret = 0; printf("---test mutext in task --- \n"); ret = rt_task_create(&task_desc1, "my_task1", 0, MAX_PRIO , T_FPU); if (ret < 0) { fprintf(stderr, "Failed to create task1: %s\n", strerror(-ret)); return -1; } ret = rt_task_create(&task_desc2, "my_task2", 0, MAX_PRIO , T_FPU); if (ret < 0) { fprintf(stderr, "Failed to create task2: %s\n", strerror(-ret)); return -1; } ret = rt_task_create(&task_desc3, "my_task3", 0, MAX_PRIO , T_FPU); if (ret < 0) { fprintf(stderr, "Failed to create task3: %s\n", strerror(-ret)); return -1; } printf("Starting my_task...\n"); TASK_DATA taskData; taskData.taskId = 1; ret = rt_task_start(&task_desc1, &task_body, &taskData); if (ret < 0) { fprintf(stderr, "Failed to start task1: %s\n", strerror(-ret)); return -1; } taskData.taskId = 2; ret = rt_task_start(&task_desc2, &task_body, &taskData); if (ret < 0) { fprintf(stderr, "Failed to start task2: %s\n", strerror(-ret)); return -1; } taskData.taskId = 3; ret = rt_task_start(&task_desc3, &task_body, &taskData); if (ret < 0) { fprintf(stderr, "Failed to start task3: %s\n", strerror(-ret)); return -1; } exit: printf("----waiting task -------00\n"); rt_task_sleep( 3000000000ULL ); printf("----task exit--------01\n"); return 0; }
[Xenomai] my_task1[6441] called regular ioctl() on /dev/rtdm/rtdm1
这是在用户端调用ioctl 在 request = 0x4 时输出的,此请求在rt函数返回-ENOSYS, 所以切换成nrt非实时处理.
————————————————
版权声明:本文为CSDN博主「wabil」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wabil/article/details/104418388
————————————————
版权声明:本文为CSDN博主「wabil」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wabil/article/details/104418388