ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

xenomai互斥锁 和信号量 api`

2022-07-07 21:34:11  阅读:208  来源: 互联网

标签:int lock device rtdm 信号量 互斥 mutex xenomai sem


在Linux线程同步机制里常用有互斥锁和信号量两种方法.

在理解为什么有些代码需要加锁后再执行,先了解一下原子操作的概念

所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,
中间不会有任何 context switch (切换到另一个线程) 
原子操作是不可分割的,在执行完毕之前不会被任何其它任务或事件中断 
——百度百科 

意思就是这种操作是单位级的操作,执行过程保证绝对不受影响,执行结果一定 .而且互斥锁必须总是由它上锁的线程解锁。

RTDM还有一种锁叫自旋锁(Spinlock),它和互斥锁的区别是:

自旋锁是一种互斥锁的实现方式,相比一般的互斥锁会在等待期间放弃cpu,自旋锁则是不断循环并测试锁的状态,这样就一直占着cpu。自旋锁:与互斥量类似,它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙等(自旋)阻塞状态。用在以下情况:锁持有的时间短,而且线程并不希望在重新调度上花太多的成本。"原地打转"(自旋)。


xenomai RTDM 模式下的互斥锁有关函数


//初始化互斥锁
void rtdm_mutex_init ( rtdm_mutex_t * mutex )
此函数初始化一个带优先级反转保护的基本互斥锁,它不允许锁的所有者递归第锁定同一个锁.

//请求互斥锁
int rtdm_mutex_lock (rtdm_mutex_t * mutex)
参数mutex, 是rtdm_mutex_init()返回的互斥句柄
这是rtdm_mutex_timedlock()的轻量级版本,表示无限超时。

//释放互斥锁
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)

//获取锁定和禁用抢占,通过停止头域

define rtdm_lock_get_irqsave(__lock, __context) \

         ((__context) = __rtdm_lock_get_irqsave(__lock))

信号量(Semaphore):信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

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) //信号量增加


Mutex/Semaphore应用场景demo########

在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

标签:int,lock,device,rtdm,信号量,互斥,mutex,xenomai,sem
来源: https://www.cnblogs.com/wangjirui/p/16456196.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有