Linux信号量(3)-内核信号量

2023-05-16

概念

Linux内核的信号量在概念和原理上和用户态的System V的IPC机制信号量是相同的,不过他绝不可能在内核之外使用,因此他和System V的IPC机制信号量毫不相干。

如果有一个任务想要获得已经被占用的信号量时,信号量会将其放入一个等待队列(它不是站在外面痴痴地等待而是将自己的名字写在任务队列中)然后让其睡眠。

当持有信号量的进程将信号释放后,处于等待队列中的一个任务将被唤醒(因为队列中可能不止一个任务),并让其获得信号量。这一点与自旋锁不同,处理器可以去执行其它代码。

应用场景

由于争用信号量的进程在等待锁重新变为可用时会睡眠,所以信号量适用于锁会被长时间持有的情况;相反,锁被短时间持有时,使用信号量就不太适宜了,因为睡眠、维护等待队列以及唤醒所花费的开销可能比锁占用的全部时间表还要长。

举2个生活中的例子:

  1. 我们坐火车从南京到新疆需要2天的时间,这个’任务’特别的耗时,只能坐在车上等着车到站,但是我们没有必要一直睁着眼睛等,理想的情况就是我们上车就直接睡觉,醒来就到站(看过《异形》的读者会深有体会),这样从人(用户)的角度来说,体验是最好的,对比于进程,程序在等待一个耗时事件的时候,没有必须要一直占用CPU,可以暂停当前任务使其进入休眠状态,当等待的事件发生之后再由其他任务唤醒,类似于这种场景采用信号量比较合适。

  2. 我们有时候会等待电梯、洗手间,这种场景需要等待的时间并不是很多,如果我们还要找个地方睡一觉,然后等电梯到了或者洗手间可以用了再醒来,那很显然这也没有必要,我们只需要排好队,刷一刷抖音就可以了,对比于计算机程序,比如驱动在进入中断例程,在等待某个寄存器被置位,这种场景需要等待的时间往往很短暂,系统开销甚至远小于进入休眠的开销,所以这种场景采用自旋锁比较合适。

关于信号量和自旋锁,以及死锁问题,我们后面会再详细讨论。

使用方法

一个任务要想访问共享资源,首先必须得到信号量,获取信号量的操作将把信号量的值减1,若当前信号量的值为负数,表明无法获得信号量,该任务必须挂起在 该信号量的等待队列等待该信号量可用;若当前信号量的值为非负数,表示能获得信号量,因而能即时访问被该信号量保护的共享资源。

当任务访问完被信号量保护的共享资源后,必须释放信号量,释放信号量通过把信号量的值加1实现,如果信号量的值为非正数,表明有任务等待当前信号量,因此他也唤醒所有等待该信号量的任务。

内核信号量的构成

内核信号量类似于自旋锁,因为当锁关闭着时,它不允许内核控制路径继续进行。然而,当内核控制路径试图获取内核信号量锁保护的忙资源时,相应的进程就被挂起。只有在资源被释放时,进程才再次变为可运行。

只有可以睡眠的函数才能获取内核信号量;中断处理程序和可延迟函数都不能使用内核信号量。

内核信号量是struct semaphore类型的对象,在内核源码中位于include\linux\semaphore.h文件

struct semaphore{
    raw_spinlock_t        lock;
    unsigned int        count;
    struct list_head    wait_list;
}
成员描述
lock在2.6.33之后的版本,内核加入了raw_spin_lock系列,使用方法和spin_lock系列一模一样,只是参数spinlock_t变为了raw_spinlock_t
count相当于信号量的值,大于0,资源空闲;等于0,资源忙,但没有进程等待这个保护的资源;小于0,资源不可用,并至少有一个进程等待资源
wait_list内核链表,当前获得信号量的任务会与该成员一起注册到等待的链表中

信号量的API

初始化

DECLARE_MUTEX(name)

该宏声明一个信号量name并初始化他的值为1,即声明一个互斥锁。

DECLARE_MUTEX_LOCKED(name)

该宏声明一个互斥锁name,但把他的初始值设置为0,即锁在创建时就处在已锁状态。因此对于这种锁,一般是先释放后获得。

void sema_init (struct semaphore *sem, int val);

该函用于数初始化设置信号量的初值,他设置信号量sem的值为val。

注意:

val设置为1说明只有一个持有者,这种信号量叫二值信号量或者叫互斥信号量。

我们还允许信号量可以有多个持有者,这种信号量叫计数信号量,在初始化时要说明最多允许有多少个持有者也可以把信号量中的val初始化为任意的正数值n,在这种情况下,最多有n个进程可以并发地访问这个资源。

void init_MUTEX (struct semaphore *sem);

该函数用于初始化一个互斥锁,即他把信号量sem的值设置为1。

void init_MUTEX_LOCKED (struct semaphore *sem);

该函数也用于初始化一个互斥锁,但他把信号量sem的值设置为0,即一开始就处在已锁状态。

PV操作

获取信号量(P)

void down(struct semaphore * sem);

该函数用于获得信号量sem,他会导致调用该函数的进程睡眠,因此不能在中断上下文(包括IRQ上下文和softirq上下文)使用该函数。该函数将把sem的值减1,如果信号量sem的值非负,就直接返回,否则调用者将被挂起,直到别的任务释放该信号量才能继续运行。

int down_interruptible(struct semaphore * sem);

该函数功能和down类似,不同之处为,down不会被信号(signal)打断,但down_interruptible能被信号打断,因此该函数有返回值来区分是正常返回还是被信号中断,如果返回0,表示获得信号量正常返回,如果被信号打断,返回-EINTR。

int down_trylock(struct semaphore * sem);

该函数试着获得信号量sem,如果能够即时获得,他就获得该信号量并返回0,否则,表示不能获得信号量sem,返回值为非0值。因此,他不会导致调用者睡眠,能在中断上下文使用。

int down_killable(struct semaphore *sem);
int down_timeout(struct semaphore *sem, long jiffies);
int down_timeout_interruptible(struct semaphore *sem, long jiffies);

释放内核信号量(V)

void up(struct semaphore * sem);

该函数释放信号量sem,即把sem的值加1,如果sem的值为非正数,表明有任务等待该信号量,因此唤醒这些等待者。

补充

int down_interruptible(struct semaphore *sem)

这个函数的功能就是获得信号量,如果得不到信号量就睡眠,此时没有信号打断,那么进入睡眠。但是在睡眠过程中可能被信号打断,打断之后返回-EINTR,主要用来进程间的互斥同步。

下面是该函数的注释:

/**
* down_interruptible - acquire the semaphore unless interrupted
* @sem: the semaphore to be acquired
*
* Attempts to acquire the semaphore. If no more tasks are allowed to
* acquire the semaphore, calling this function will put the task to sleep.
* If the sleep is interrupted by a signal, this function will return -EINTR.
* If the semaphore is successfully acquired, this function returns 0.
*/

一个进程在调用down_interruptible()之后,如果sem<0,那么就进入到可中断的睡眠状态并调度其它进程运行, 但是一旦该进程收到信号,那么就会从down_interruptible函数中返回。并标记错误号为:-EINTR。

一个形象的比喻:传入的信号量为1好比天亮,如果当前信号量为0,进程睡眠,直到(信号量为1)天亮才醒,但是可能中途有个闹铃(信号)把你闹醒。

又如:小强下午放学回家,回家了就要开始吃饭嘛,这时就会有两种情况:
情况一:饭做好了,可以开始吃;
情况二:当他到厨房去的时候发现妈妈还在做,
妈妈就对他说:“你先去睡会,待会做好了叫你。”
小强就答应去睡会,不过又说了一句:“睡的这段时间要是小红来找我玩,你可以叫醒我。”
小强就是down_interruptible,想吃饭就是获取信号量,睡觉对应这里的休眠,而小红来找我玩就是中断休眠。

使用可被中断的信号量版本的意思是,万一出现了semaphore的死锁,还有机会用ctrl+c发出软中断,让等待这个内核驱动返回的用户态进程退出。而不是把整个系统都锁住了。在休眠时,能被中断信号终止,这个进程是可以接受中断信号的!

比如你在命令行中输入# sleep 10000,按下ctrl + c,就给上面的进程发送了进程终止信号。信号发送给用户空间,然后通过系统调用,会把这个信号传给递给驱动。信号只能发送给用户空间,无权直接发送给内核的,那1G的内核空间,我们是无法直接去操作的。

内核信号量的使用例程

场景1

在驱动程序中,当多个线程同时访问相同的资源时(驱动中的全局变量时一种典型的共享资源),可能会引发“竞态“,因此我们必须对共享资源进行并发控制。Linux内核中

解决并发控制的最常用方法是自旋锁与信号量(绝大多数时候作为互斥锁使用)。

在这里插入图片描述

场景2

有时候我们希望设备只能被一个进程打开,当设备被占用的时候,其他设备必须进入休眠。

信号处理示意图

在这里插入图片描述

如上图:

  1. 进程A首先通过open()打开设备文件,调用到内核的hello_open(),并调用down_interruptible(),因为此时信号量没有被占用,所以进程A可以获得信号量;

  2. 进程A获得信号量之后继续处理原有任务,此时进程B也要通过open()打开设备文件,同样调用内核函数hello_open(),但此时信号量获取不到,于是进程B被阻塞;

  3. 进程A任务执行完毕,关闭设备文件,并通过up()释放信号量,于是进程B被唤醒,并得以继续执行剩下的任务,

  4. 进程B执行完任务,释放设备文件,通过up()释放信号量

代码如下:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/semaphore.h>

static int major = 250;
static int minor = 0;
static dev_t devno;
static struct cdev cdev;


static struct class *cls;
static struct device *test_device;

static struct semaphore sem;
static int hello_open (struct inode *inode, struct file *filep)
{
    
    if(down_interruptible(&sem))//p
    {
        return -ERESTARTSYS;
    }
      return 0;
}
static int hello_release (struct inode *inode, struct file *filep)
{
    up(&sem);//v
    return 0;
}
static struct file_operations hello_ops =
{
    .open = hello_open,
    .release = hello_release,
};
static int hello_init(void)
{
    int result;
    int error;    
    printk("hello_init \n");
    result = register_chrdev( major, "hello", &hello_ops);
    if(result < 0)
    {
        printk("register_chrdev fail \n");
        return result;
    }
    devno = MKDEV(major,minor);
    cls = class_create(THIS_MODULE,"helloclass");
    if(IS_ERR(cls))
    {
        unregister_chrdev(major,"hello");
        return result;
    }
    test_device = device_create(cls,NULL,devno,NULL,"test");
    if(IS_ERR(test_device ))
    {
        class_destroy(cls);
        unregister_chrdev(major,"hello");
        return result;
    }
    sem_init(&sem,1);
    return 0;
}
static void hello_exit(void)
{
    printk("hello_exit \n");
    device_destroy(cls,devno);    
    class_destroy(cls);
    unregister_chrdev(major,"hello");
    return;
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("daniel.peng")

测试程序 test.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
main()
{
    int fd;
    
    printf("before open\n ");    
    fd = open("/dev/test",O_RDWR);  //原子变量  0
    if(fd<0)
    {
        perror("open fail \n");
        return;
    }
    printf("open ok ,sleep......\n ");    
    sleep(20);
    printf("wake up from sleep!\n ");        
    close(fd);   //加为1
}

编译步骤

1 make 生成 hello.ko

2 gcc test.c -o a

3 gcc test.c -o b

测试步骤

  1. 安装驱动
insmod hello.ko
  1. 先运行进程A,在运行进程B

可见进程A成功打开设备,在进程A sleep期间会一直占有该字符设备,进程B由于无法获得信号量,进入休闲,结合代码可知,进程B被阻塞在函数open()中。

  1. 进程A 结束了sleep,并释放字符设备以及信号量,进程B被唤醒获得信号量,并成功打开了字符设备。

  1. 进程B执行完sleep函数后退出,并释放字符设备和信号量。

读-写信号量

跟自旋锁一样,信号量也有区分读-写信号量之分。

如果一个读写信号量当前没有被写者拥有并且也没有写者等待读者释放信号量,那么任何读者都可以成功获得该读写信号量;否则,读者必须被挂起直到写者释放该信号量。如果一个读写信号量当前没有被读者或写者拥有并且也没有写者等待该信号量,那么一个写者可以成功获得该读写信号量,否则写者将被挂起,直到没有任何访问者。因此,写者是排他性的,独占性的。

读写信号量有两种实现,一种是通用的,不依赖于硬件架构,因此,增加新的架构不需要重新实现它,但缺点是性能低,获得和释放读写信号量的开销大;另一种是架构相关的,因此性能高,获取和释放读写信号量的开销小,但增加新的架构需要重新实现。在内核配置时,可以通过选项去控制使用哪一种实现。

读写信号量的相关API:

DECLARE_RWSEM(name)

该宏声明一个读写信号量name并对其进行初始化。

void init_rwsem(struct rw_semaphore *sem);

该函数对读写信号量sem进行初始化。

void down_read(struct rw_semaphore *sem);

读者调用该函数来得到读写信号量sem。该函数会导致调用者睡眠,因此只能在进程上下文使用。

int down_read_trylock(struct rw_semaphore *sem);

该函数类似于down_read,只是它不会导致调用者睡眠。它尽力得到读写信号量sem,如果能够立即得到,它就得到该读写信号量,并且返回1,否则表示不能立刻得到该信号量,返回0。因此,它也可以在中断上下文使用。

void down_write(struct rw_semaphore *sem);

写者使用该函数来得到读写信号量sem,它也会导致调用者睡眠,因此只能在进程上下文使用。

int down_write_trylock(struct rw_semaphore *sem);

该函数类似于down_write,只是它不会导致调用者睡眠。该函数尽力得到读写信号量,如果能够立刻获得,就获得该读写信号量并且返回1,否则表示无法立刻获得,返回0。它可以在中断上下文使用。

void up_read(struct rw_semaphore *sem);

读者使用该函数释放读写信号量sem。它与down_read或down_read_trylock配对使用。

如果down_read_trylock返回0,不需要调用up_read来释放读写信号量,因为根本就没有获得信号量。

void up_write(struct rw_semaphore *sem);

写者调用该函数释放信号量sem。它与down_write或down_write_trylock配对使用。如果down_write_trylock返回0,不需要调用up_write,因为返回0表示没有获得该读写信号量。

void downgrade_write(struct rw_semaphore *sem);

该函数用于把写者降级为读者,这有时是必要的。因为写者是排他性的,因此在写者保持读写信号量期间,任何读者或写者都将无法访问该读写信号量保护的共享资源,对于那些当前条件下不需要写访问的写者,降级为读者将,使得等待访问的读者能够立刻访问,从而增加了并发性,提高了效率。

读写信号量适于在读多写少的情况下使用,在linux内核中对进程的内存映像描述结构的访问就使用了读写信号量进行保护。

更多嵌入式干货请关注 一口Linux

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux信号量(3)-内核信号量 的相关文章

  • c大小为0的数组

    大小为0的数组 Q xff1a 数组大小为0应该怎么理解 xff1f 比如 xff1a struct page page 0 unsigned long private 0 cacheline aligned A xff1a 一个很好的例子
  • 【安装ROS执行rosdep init、rosdep update失败-本地解决方法】

    Ubuntu系统安装ROS时 xff0c 执行rosdep init rosdep update失败 本地解决方法 1 克隆镜像文件2 修改20 default list文件3 修改sources list py文件文件3 1 执行命令3
  • 中兴2016校招软件在线笔试题

    面试经验可以参考我的另一篇文章 xff0c 是7月初参加openday面试的 xff0c 文章链接http blog csdn net dandelion1314 article details 47009585 招聘群里有人发的招聘时间安
  • docker 图形化界面portainer

    portainer 官方地址 https portainer readthedocs io en latest deployment html 网易镜像网站https c 163yun com hub m home 国内拉去镜像 docke
  • ST电机库v5.4.4源代码分析(6): PID以及相关参数

    编者 xff1a 沉尸 5912129 64 qq com 前言 xff1a 本文章探索st电机库自动生成的PID参数的由来 xff0c 采用的控制板为野火407电机板 43 BLDC带Hall的电机 在 Mcboot 函数中初始化变量 P
  • 【Pixhawk】注册一个字符型驱动设备

    最近学习Pixhawk的SPI xff0c 本以为PX4是STM32单片机而已 xff0c 写个SPI驱动应该很简单 但是当我看到mpu9250的那些cpp文件 xff0c 我一下就蒙了 由于PX4用的NUTTX系统 xff0c 类似Lin
  • 电脑开机过程(腾讯08年面试题)

    打开电源启动机器几乎是电脑爱好者每天必做的事情 xff0c 面对屏幕上出现的一幅幅启动画面 xff0c 我们一点儿也不会感到陌生 xff0c 但是 xff0c 计算机在显示这些启动画面时都做了些什么工作呢 xff1f 相信有的朋友还不是很清
  • 卡尔曼滤波的理解以及推导过程

    针对的系统为 xff1a 状态方程 X k 61 AX k 1 43 Bu k 1 43 W k 1 测量方程 Z k 61 HX k 43 V k 0 W是状态预测的噪声 符合正态分布N 0 Q V 是测量的噪声 符合正态分布N 0 R
  • 车载网络技术——CAN总线基础

    在之前一文 xff0c 简单介绍了一下具有概括性的车载网络技术的基础知识点 xff0c 那么在本文 xff0c 将专注于介绍CAN总线的相关知识 首先 xff0c 回忆一下之前提到的现场总线 xff0c 它是工业环境下的一种应用技术 xff
  • 树莓派3B装系统后无法正常启动的可能原因

    新入手树莓派3B xff0c 按照网上的教程尝试用NOOBS和Raspbian两种方式安装系统 教程里的过程是很简单的 xff0c 但无论用哪种方法 xff0c 我的树莓派3B都无法正常启动 上电后只有红灯亮 xff0c 绿色指示灯不亮 网
  • 几种常见的调度算法

    文章目录 1 先来先服务算法 xff08 FCFS First Come First Service xff09 2 短作业优先算法 xff08 SJF Short Job First xff09 3 高响应比优先算法4 时间片轮转算法5
  • ROVIO解析

    http jinjaysnow github io blog 2017 07 ROVIO E8 A7 A3 E6 9E 90 html 基于EKF的鲁棒视觉惯性测量Robust Visual Inertial Odometry ROVIO
  • PLC前途如何,大学生能学吗,不要指望学会PLC就能月薪15000

    我这里没有鸡汤也没有鸭汤 xff0c 都是实在大白话 xff0c 技术出身的人大概都有点固执 xff0c 但是很务实 xff0c 总是认为只要把技术掌握了学好了 xff0c 就能拿到理想的工资 但是这句话也不能说没道理 xff0c 任何事物
  • 给自动化专业的大学生的终极警钟,单片机、PLC、嵌入式等方向哪个才是香饽饽?

    从面向工资的角度来说 xff0c 假设你不升学历的话 xff0c 推荐优先选择序列如下 xff1a 1 嵌入式 xff08 ARM 43 Linux xff09 xff1a 可对接工业机器人 物联网 高端3C产品设计 xff0c 但要去补课
  • STM32F1和STM32F4这两个系列都是单片机达人的心头好,到底那个好

    STM32F1和STM32F4这两个系列都是单片机达人的心头好 xff0c 到底那个好呢 大家都知道GD32是国内开发的一款单片机 xff0c 能够说是国货之光 xff0c 据说开发的人员是来自ST公司的 xff0c GD32也是以STM3
  • 嵌入式老师傅告诉你单片机6年想转嵌入式Linux值不值得

    嵌入式老师傅告诉你单片机6年想转嵌入式Linux值不值得 一 你真的决定要转嵌入式Linux吗 xff1f 要不要从单片机转嵌入式Linux是一个影响到职业开展的严肃决策 xff0c 我不能帮你拿主见 xff0c 只能帮你列出利弊 xff0
  • STM32收入高也好找工作,所以我学嵌入式linux终究是错付了吗

    STM32收入高也好找工作 xff0c 所以我学嵌入式linux终究是错付了吗 经常有同学纠结问我 xff1a 我到底是学STM32还是学嵌入式linux 这个问题很多人都会有自己的看法 xff0c 今天我试着从多个角度 xff0c 把了解
  • linux下close无法关闭socket

    由于close之后阻塞的recv出现不能立即返回关闭 xff0c socket进入被动一方 这种情况多数是创建和关闭处于不同的线程 解决办法在调用close函数之前先调用shutdown socket SHUT RDWR 函数
  • FPGA是什么呢,通透讲解单片机和FPGA的区别

    FPGA是什么呢 xff0c 通透讲解单片机和FPGA的区别 插播一条 xff1a 我自己在今年年初录制了一套还比较系统的入门单片机教程 xff0c 想要的同学找我拿就行了免費的 xff0c 私信我就可以哦 点我头像黑色字体加我地球呺也能领
  • 摊牌了我后悔入行了,浅谈为何不该入行嵌入式

    摊牌了我后悔入行了 xff0c 浅谈为何不该入行嵌入式 插播一条 xff1a 我自己在今年年初录制了一套还比较系统的入门单片机教程 xff0c 想要的同学找我拿就行了免費的 xff08 禾厶 亻言 手戈 xff09 最近比较闲 xff0c

随机推荐

  • 关于嵌入式Linux做底层还是应用,要掌握什么技能

    关于嵌入式Linux做底层还是应用 xff0c 要掌握什么技能 插播一条 xff1a 我自己在今年年初录制了一套还比较系统的入门单片机教程 xff0c 想要的同学找我拿就行了免費的 xff08 禾厶 亻言 手戈 xff09 最近比较闲 xf
  • c语言必背的100代码

    c语言必背的100代码 插播一条 xff1a 自己在今年整理一套单片机单片机相关论文800余篇 论文制作思维导图 原理图 43 源代码 43 开题报告 43 正文 43 外文资料 想要的同学私信找我 我记得刚开始接触编程的时候 xff0c
  • 51单片机简介

    51单片机简介 插播一条 xff1a 文章末尾有惊喜哟 一 51单片机标识信息 通常我们所说的51单片机是指以51内核扩展出的单片机 出产51单片机的厂商很多 xff0c 51单片机的型号也很多 下表列出了一些51单片机的厂商和型号 以上提
  • 都2022年了,互联网与嵌入式怎么选?

    都2022年了 xff0c 互联网与嵌入式怎么选 xff1f 2022届应届毕业生前来作答一波 大家找工作最关心的还是薪资待遇问题 从今年的校招情况来看 xff0c 互联网中的算法岗是要高于嵌入式的 xff0c 而开发岗整体和嵌入式持平 从
  • 做工程师还是转型做产品经理?

    做工程师还是转型做产品经理 xff1f 其实在国内互联网萌芽之初 xff0c 技术 产品 设计 运营职位其实区分的不是特别明显 xff0c 往往是一人身兼多职 xff0c 但随着行业的成熟 xff0c 这些职位之间的分工才逐渐细化 xff1
  • 为什么游戏里的都是伪随机,做不出真随机?

    为什么游戏里的都是伪随机 xff0c 做不出真随机 xff1f 希望来个简单易懂的解释 xff1f 我发现像LOL这些游戏 xff0c 暴击机制都是伪随机的 xff0c 前面几下没暴击 xff0c 后面暴击几率很大概率 像王者荣耀更为明显
  • 高学历毕业生,该学单片机还是plc?

    高学历毕业生 xff0c 该学单片机还是plc xff1f 研究生阶段 xff0c 使用欧姆龙和西门子的PLC做过一些商用的项目 xff0c 但是在课题研究过程中因为偏向于控制算法的落地实现 xff08 借助SOC 43 FPGA xff0
  • 无人机飞控平台ArduPilot源码入门教程 - 首页

    原文链接 简介 ArduPilot代码库有点大 核心的ardupilot git树大概有70万行代码 对新人来说这有点吓人 这个文档打算给出一点建议 关于如何快速上手相关代码 我们假设你熟悉C 43 43 的关键概念 另外好多例子都是假设你
  • C++ 常见面试和笔试坑点总结(持续更新)

    题目一 xff1a 下面的程序是执行if还是else span class hljs keyword int span a 61 span class hljs number 2 span span class hljs keyword i
  • 速腾聚创32线雷达雷达,RVIZ显示激光点云

    1 下载驱动文件 ahren 64 ahren ld ws src git clone https github com RoboSense LiDAR ros rslidar 2 在工作空间ld ws目录下编译 ahren 64 ahre
  • Attitude Control (Copter Code Overview)

    Attitude Control Copter Code Overview Between AC3 1 5 and AC 3 2 the attitude control logic was restructured as part of
  • ROS使用OpenCV读取图像并发布图像消息在rviz中显示

    思路 xff1a xff08 1 xff09 使用opencv读取本地图像 xff08 2 xff09 调用cv bridge CvImage xff08 xff09 toImageMsg 将本地图像发送给rviz显示 1 使用opencv
  • 关于ASP.NET 不允许所请求的注册表访问权。

    这个问题困扰了我一天 xff0c 到现在头还是疼的 xff0c 参考了网上N个解决办法 xff0c 最后问了孟宪会老师 xff0c 老师说 匿名账户没有访问注册表的权限 xff0c 通过老师提醒 xff0c 我试着启用GUEST账户 xff
  • ASP.NET网站安装部署,加入注册码验证等等

    最近通过自己实践 xff0c 完成了ASP NET网站安装部署 xff0c 实现了SQL打包 xff0c 实现了配置文件的打包等等 xff0c 并实现了注册码的验证等等 xff0c 如有需要请跟帖 xff0c 留下联系方式
  • 手把手教你Asp.net三层架构

    首先简单介绍下三层乃至多层架构 xff08 高手跳过 xff09 xff1a BLL 就是business Logic laywer xff08 业务逻辑层 xff09 他只负责向数据提供者也就是DAL调用数据 然后传递给客户程序也就是UI
  • ASP.NET 自定义控件 自定义属性的使用

    最近在给公司一个老的ASP平台进行改版 xff0c 由于这个平台运行时间太长 xff0c 期间有很多程序员进行过修改 xff0c 导致数据库显得很乱 在实际改版时架构采用了多层架构 xff0c 引入工厂模式 xff0c 面向接口 对于资讯类
  • 我的2011之—混迹于中等城市的.net程序员

    眼瞅着走过了2011年 xff0c 过了这一年我就奔三了 2011年完成了几件大事 xff1a 生了儿子 xff0c 买了房子 按说这生活的本质在逐步体现 xff0c 小日子也算凑合吧 可是怎么确无法高兴起来 到底是为什么呢 xff1f 说
  • 树莓派3B+踩坑记录:一、安装Ubuntu Mate

    树莓派3B 43 踩坑记录 xff1a 一 安装Ubuntu Mate 2020 07 27 05 44 15 来源 互联网 分类 xff1a 相关文章 树莓派3B 43 踩坑记录 xff1a 一 安装Ubuntu Mate 树莓派 xff
  • 1. 从0开始学ARM-安装Keil MDK uVision集成开发环境

    关于ARM的一些基本概念 xff0c 大家可以参考我之前的文章 xff1a 到底什么是Cortex ARMv8 arm架构 ARM指令集 soc xff1f 一文帮你梳理基础概念 科普 二 安装Keil MDK uVision集成开发环境
  • Linux信号量(3)-内核信号量

    概念 Linux内核的信号量在概念和原理上和用户态的System V的IPC机制信号量是相同的 xff0c 不过他绝不可能在内核之外使用 xff0c 因此他和System V的IPC机制信号量毫不相干 如果有一个任务想要获得已经被占用的信号