xenomai互斥锁 和信号量 api`


在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

原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/271877.html

(0)
上一篇 2022年7月8日
下一篇 2022年7月8日

相关推荐

发表回复

登录后才能评论