从零开始学习UCOSII操作系统7--信号量

2023-05-16

从零开始学习UCOSII操作系统7--信号量


参考博客:@ http://blog.csdn.net/gatiemehttps://blog.csdn.net/gatieme/article/details/21071379

前言:这里一定要分析清楚,因为信号量分析清楚后,后面的邮箱等其他的通信的东西都是大同小异的。

1、信号量的组成

(1)一部分是16位无符号的整型信号量计数值(0~65536)

(2)另一部分是由等待信号量的任务组成的等待任务表。

(3)信号量的6个基本函数:
OSSemAccept(), OSSemCreate(),OSSemDel()
OSSemPend(),OSSemPost()以及OSSemQuery()

其中要使用这些信号量的函数,必须在OS_CFG.h中将配置常数置为1,这样UCOSII才能支持信号量。

当OS_SEM_EN设为0的时候,所有的信号量都不能使用。
需要使用这些函数的时候,需要把这些宏定义置为1;

2、信号量使用的函数

(1)OSSemAccept(),OSSemPost()以及OSSemQuery()函数可以由任务或者中断服务子程序调用。

(2)OSSemDel()和OSSemPend()函数只能由任务程序调用。

3、信号量的两个关键问题

(1)任务怎么得到一个信号量的问题?

想要得到一个信号量的任务,必须执行等待的操作(pend)
如果信号量有效(非0),则信号量减1,任务继续运行。

如果此时信号量无效,则等待信号量的任务就被列入等待信号量的任务表中。此时可以设置超时时间,如果等待了多少时间后,仍然没有信号发生。
则此任务进入就绪态,准备运行,并且显示出错的代码---等待超时失败。

(2)任务对信号量的释放问题
任务执行发信号的POST操作来释放信号量,如果没有任务等待该信号量,那么这个信号量的值就是仅仅简单的+1.则此时信号量大于0有效。

如果有任务等待该信号量,那么就会有另一个任务进入就绪态,此时信号量就不+1了,因为刚刚的信号量就用出去了。

4、信号量的有效与无效问题

信号量有效:信号量的计算器非0,信号量有效表示任务对资源可用。

信号量无效:信号量的计算器为0,信号量无效表示任务对目前的资源不可用,需要等待其他的另一个任务或者中断服务子程序发出该信号量。

5信号量的值OSEventCnt大小表示什么?

二值信号量Mutext,表示任务可以独占共享资源

计数型的信号量Semaphore,用于某资源可同时为N个任务所用。

二值信号量与互斥型信号量的区别:

互斥型信号量必须是同一个任务申请,同一个任务释放,其他的任务释放无效。

二值信号量,一个任务申请成功后,可以由另一个任务释放,也可以由本任务释放。

6、信号量是如何实现任务之间的通信的?

(1)信号量的建立必须在任务级中建立。

(2)信号量类型为OS_EVENT,信号量值可以为1和0(二值信号量),0~65536计数型的信号量,不同的值代表不同的意义。

(3)对于互斥型信号量来说,就两个操作,请求和释放。

(4)一个任务请求信号量的时候,如果被其他的任务占用,则任务等待,同时导致任务切换。 如果没有被其他任务占用,则获得,继续执行。

(5)释放信号量的时候,如果其他高优先级任务正在请求并且等待该信号量的时候,则导致任务切换。

(6)OSSemAccept(信号量)起到查询信号量的作用,返回信号量的值。

(7)OSSemPend(Sem,timeout,&err);
timeout代表等待timeout个信号量后还没有得到信号量,恢复到就绪的状态,如果timeout=0,标志等待无限信号量。

7、信号量的三个关键函数的代码分析

(1)OSSemCreate()创建一个信号量(由任务或者启动代码操作)
创建工作必须在任务级代码中或者多任务启动之前完成。功能只要是先获取一个事件控制块ECB,写入一些参数,其中调用了OS_EventWaitListInit()函数,对事件控制块的等待任务列表进行初始化。

就是将事件控制块定义为信号量,然后把该填写的量填写。最后设置信号量的初始值

OS_EVENT  *OSSemCreate (INT16U cnt)
{
    OS_EVENT  *pevent;
#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
    OS_CPU_SR  cpu_sr = 0;
#endif



    if (OSIntNesting > 0) {                                /* 中断服务不能创建信号量  */
        return ((OS_EVENT *)0);                           
    }
    OS_ENTER_CRITICAL();
    pevent = OSEventFreeList;                              /* 得到下一个空闲的事件空闲控制块 */
    if (OSEventFreeList != (OS_EVENT *)0) {                /* See if pool of free ECB pool was empty   */
        OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
    }
    OS_EXIT_CRITICAL();
    if (pevent != (OS_EVENT *)0) {                         /* Get an event control block               */
        pevent->OSEventType    = OS_EVENT_TYPE_SEM;
        pevent->OSEventCnt     = cnt;                      /* 设置信号量的初始值                      */
        pevent->OSEventPtr     = (void *)0;                /* Unlink from ECB free list                */
#if OS_EVENT_NAME_SIZE > 1
        pevent->OSEventName[0] = '?';                      /* Unknown name                             */
        pevent->OSEventName[1] = OS_ASCII_NUL;
#endif
        OS_EventWaitListInit(pevent);                      /* Initialize to 'nobody waiting' on sem.   */
    }
    return (pevent);
}

(2)删除一个信号量
1、删除一个信号量的函数OSSemDel()的源代码,当文件OS_CFG.h中的OS_SEM_DEL_EN为1的时候,该代码才被编译。

2、总之,在删除信号量之前,必须首先删除操作该信号量的所有的任务。

3、进入switch中,当OPT为OS_DEL_NO_PEND,并且没有任务在等待该信号量的时候,OSSemDel()函数将事件控制块ECB标志为未使用,并将其退回到空闲事件控制链表中,此操作允许该事件用于创建另一个信号量。

当OPT为OS_DEL_ALWAYS时候,所有等待该信号的任务都将进入就绪态,每个任务都得到了该信号量,当然这样可能会导致致命的后果,因为采用信号量就是为了防止对资源的多重访问。

OS_EVENT  *OSSemDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
{
    BOOLEAN    tasks_waiting;
    OS_EVENT  *pevent_return;
#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
    OS_CPU_SR  cpu_sr = 0;
#endif

#if OS_ARG_CHK_EN > 0
    if (err == (INT8U *)0) {                               /* Validate 'err'                           */
        return (pevent);
    }
    if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
        *err = OS_ERR_PEVENT_NULL;
        return (pevent);
    }
#endif
    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {        /* 是否是指向某一个用于信号量的一个函数             */
        *err = OS_ERR_EVENT_TYPE;
        return (pevent);
    }
    if (OSIntNesting > 0) {                                /* See if called from ISR ...               */
        *err = OS_ERR_DEL_ISR;                             /* ... can't DELETE from an ISR             */
        return (pevent);
    }
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0) {                         /* 看是否有任务在等待信号量  */
        tasks_waiting = OS_TRUE;                           /* 是的                                     */
    } else {
        tasks_waiting = OS_FALSE;                          /* No                                       */
    }
    switch (opt) {
        case OS_DEL_NO_PEND:                               /* Delete semaphore only if no task waiting */
             if (tasks_waiting == OS_FALSE) {
#if OS_EVENT_NAME_SIZE > 1
                 pevent->OSEventName[0] = '?';             /* Unknown name                             */
                 pevent->OSEventName[1] = OS_ASCII_NUL;
#endif
                 pevent->OSEventType    = OS_EVENT_TYPE_UNUSED;
                 pevent->OSEventPtr     = OSEventFreeList; /* Return Event Control Block to free list  */
                 pevent->OSEventCnt     = 0;
                 OSEventFreeList        = pevent;          /* Get next free event control block        */
                 OS_EXIT_CRITICAL();
                 *err                   = OS_NO_ERR;
                 pevent_return          = (OS_EVENT *)0;   /* Semaphore has been deleted               */
             } else {
                 OS_EXIT_CRITICAL();
                 *err                   = OS_ERR_TASK_WAITING;
                 pevent_return          = pevent;
             }
             break;

        case OS_DEL_ALWAYS:                                /* Always delete the semaphore              */
             while (pevent->OSEventGrp != 0) {             /* Ready ALL tasks waiting for semaphore    */
                 (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM);
             }
#if OS_EVENT_NAME_SIZE > 1
             pevent->OSEventName[0] = '?';                 /* Unknown name                             */
             pevent->OSEventName[1] = OS_ASCII_NUL;
#endif
             pevent->OSEventType    = OS_EVENT_TYPE_UNUSED;
             pevent->OSEventPtr     = OSEventFreeList;     /* Return Event Control Block to free list  */
             pevent->OSEventCnt     = 0;
             OSEventFreeList        = pevent;              /* Get next free event control block        */
             OS_EXIT_CRITICAL();
             if (tasks_waiting == OS_TRUE) {               /* Reschedule only if task(s) were waiting  */
                 OS_Sched();                               /* Find highest priority task ready to run  */
             }
             *err                   = OS_NO_ERR;
             pevent_return          = (OS_EVENT *)0;       /* Semaphore has been deleted               */
             break;

        default:
             OS_EXIT_CRITICAL();
             *err                   = OS_ERR_INVALID_OPT;
             pevent_return          = pevent;
             break;
    }
    return (pevent_return);
}
#endif

(3)等待一个信号量OSSEMPend()

等待一个信号量函数的源代码分析:

PS:设置该函数中的超时时间,真正实现的函数是在OSTimeTICK()函数中逐个的递减。这个地方要注意下,对每个任务的任务控制块TCB中的OSTCBDly做递减操作。

最后的参数:perr就是指向一个错误的标志。

void  OSSemPend (OS_EVENT  *pevent,
                 INT32U     timeout,
                 INT8U     *perr)
{

#ifdef OS_SAFETY_CRITICAL
    if (perr == (INT8U *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
    }
#endif

#if OS_ARG_CHK_EN > 0u
    if (pevent == (OS_EVENT *)0) {                    /* 判断这个指针是否为空指针                            */
        *perr = OS_ERR_PEVENT_NULL;
        return;
    }
#endif
    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* 如果这个事件控制块的类型不是信号量的话                 */
        *perr = OS_ERR_EVENT_TYPE;
        return;
    }
    if (OSIntNesting > 0u) {                          /* 不在中断中操作此函数  */
        *perr = OS_ERR_PEND_ISR;                      /* ... can't PEND from an ISR                    */
        return;
    }
    if (OSLockNesting > 0u) {                         /* See if called with scheduler locked ...       */
        *perr = OS_ERR_PEND_LOCKED;                   /* ... can't PEND when locked                    */
        return;
    }
    OS_ENTER_CRITICAL();
    if (pevent->OSEventCnt > 0u) {                    /* If sem. is positive, resource available ...   */
        pevent->OSEventCnt--;                         /* ... decrement semaphore only if positive.     */
        OS_EXIT_CRITICAL();
        *perr = OS_ERR_NONE;
        return;
    }
                                                      /* Otherwise, must wait until event occurs       */
    OSTCBCur->OSTCBStat     |= OS_STAT_SEM;           /* 资源没有异常的话,那么就把资源定义为信号量 */
    OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;
    OSTCBCur->OSTCBDly       = timeout;               /* 设置信号量的超时时间 */
    OS_EventTaskWait(pevent);                         /* 使一个任务进入等待某事件发生状态 */
    OS_EXIT_CRITICAL();
    OS_Sched();                                       /* Find next highest priority task ready         */
    OS_ENTER_CRITICAL();
    switch (OSTCBCur->OSTCBStatPend) {                /* See if we timed-out or aborted                */
        case OS_STAT_PEND_OK:
             *perr = OS_ERR_NONE;
             break;

        case OS_STAT_PEND_ABORT:
             *perr = OS_ERR_PEND_ABORT;               /* Indicate that we aborted                      */
             break;

        case OS_STAT_PEND_TO:
        default:
             OS_EventTaskRemove(OSTCBCur, pevent);
             *perr = OS_ERR_TIMEOUT;                  /* Indicate that we didn't get event within TO   */
             break;
    }
    OSTCBCur->OSTCBStat          =  OS_STAT_RDY;      /* Set   task  status to ready                   */
    OSTCBCur->OSTCBStatPend      =  OS_STAT_PEND_OK;  /* Clear pend  status                            */
    OSTCBCur->OSTCBEventPtr      = (OS_EVENT  *)0;    /* Clear event pointers                          */
#if (OS_EVENT_MULTI_EN > 0u)
    OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
#endif
    OS_EXIT_CRITICAL();
}

(4)发出一个信号量:OSSEMPOST()

当任务发出一个等待的信号量之后,那么它必须接收到任务或者中断服务子程序给他发出相应的信号量,那么他才能回到就绪态,不然的话,就会不断的存在在事件控制等待列表中。

OS_EventTaskRdy()函数把优先级最高的任务从等待任务列表中去除,并使它进入就绪态,然后,调用OSSched()任务调用函数,因为已经获得信号量的任务,并且检车一下是否是最高的优先级的就绪态任务,如果是优先级最高的就绪态任务,这时就要进行任务切换,准备执行该就绪态任务。如果得到这个信号量的任务不是最高优先级的任务,退回到这个函数,并继续执行。

INT8U  OSSemPost (OS_EVENT *pevent)
{

#if OS_ARG_CHK_EN > 0u
    if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
        return (OS_ERR_PEVENT_NULL);
    }
#endif
    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* Validate event block type                     */
        return (OS_ERR_EVENT_TYPE);
    }
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0u) {                   /* 查看是否是存在信号量 */
                                                      /* 检查一下是否有任务在等待该信号量                */
        (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK);
        OS_EXIT_CRITICAL();
        OS_Sched();                                   /* Find HPT ready to run                         */
        return (OS_ERR_NONE);
    }
    if (pevent->OSEventCnt < 65535u) {                /* Make sure semaphore will not overflow         */
        pevent->OSEventCnt++;                         /* Increment semaphore count to register event   */
        OS_EXIT_CRITICAL();
        return (OS_ERR_NONE);
    }
    OS_EXIT_CRITICAL();                               /* Semaphore value has reached its maximum       */
    return (OS_ERR_SEM_OVF);
}

(5)无等待的请求一个信号量OSSemAccept()

有些书籍或者博主称为查询信号量。

解释:当一个任务请求一个信号量的时候,如果该信号量暂停无效,也可以让该任务简单的返回,而不是进入休眠的状态,这种情况下面的操作是由OSSEMAccept()函数完成的。

也就是别人家称为很牛逼的词语:非阻塞函数

有我就响应,没有那么我就继续执行。

这个函数十分的简单:从该信号量的事件控制块中取出当前的计数值,并检查该信号量是否有效(计数值是否为非0值)

如果信号量有效的话,则信号量的计数值减1,
如果信号量无效的话,那么就直接返回。

INT16U  OSSemAccept (OS_EVENT *pevent)
{
    INT16U     cnt;

#if OS_ARG_CHK_EN > 0u
    if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
        return (0u);
    }
#endif
    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* Validate event block type                     */
        return (0u);
    }
    OS_ENTER_CRITICAL();
    cnt = pevent->OSEventCnt;
    if (cnt > 0u) {                                   /* See if resource is available                  */
        pevent->OSEventCnt--;                         /* Yes, decrement semaphore and notify caller    */
    }
    OS_EXIT_CRITICAL();
    return (cnt);                                     /* Return semaphore count                        */
}

(6)查询一个信号量的当前的状态OSSemQuery()

这里面使用的,内存拷贝的方法,不断把源地址的内容,也就是源数据结构的成员,赋值到现在地址的成员中。

这段代码可能使用到了很多高级应用,但是我觉得是不好的,因为我们可以设置一个结构体,来对应事件控制块的成员。

然后一一赋值,可读性大大的提高了,做过开发的都知道,代码又丑又长,可读性没有的话,维护的成本会大大的提高。我们不是追求省那么一丁点的内存。而是后面的人维护起来比较爽。

INT8U  OSSemQuery (OS_EVENT     *pevent,
                   OS_SEM_DATA  *p_sem_data)
{
    INT8U       i;
    OS_PRIO    *psrc;
    OS_PRIO    *pdest;
#if OS_CRITICAL_METHOD == 3u                               /* Allocate storage for CPU status register */
    OS_CPU_SR   cpu_sr = 0u;
#endif



#if OS_ARG_CHK_EN > 0u
    if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
        return (OS_ERR_PEVENT_NULL);
    }
    if (p_sem_data == (OS_SEM_DATA *)0) {                  /* Validate 'p_sem_data'                    */
        return (OS_ERR_PDATA_NULL);
    }
#endif
    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {        /* Validate event block type                */
        return (OS_ERR_EVENT_TYPE);
    }
    OS_ENTER_CRITICAL();
    p_sem_data->OSEventGrp = pevent->OSEventGrp;           /* Copy message mailbox wait list           */
    psrc                   = &pevent->OSEventTbl[0];
    pdest                  = &p_sem_data->OSEventTbl[0];
    for (i = 0u; i < OS_EVENT_TBL_SIZE; i++) {
        *pdest++ = *psrc++;
    }
    p_sem_data->OSCnt = pevent->OSEventCnt;                /* Get semaphore count                      */
    OS_EXIT_CRITICAL();
    return (OS_ERR_NONE);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从零开始学习UCOSII操作系统7--信号量 的相关文章

  • Java课程设计之学习成绩管理系统

    package System import java awt import java awt event import java io import javax swing import javax swing table Abstract
  • 6.OS运行机制(补充)

    中断
  • plsql更改用户登录密码

    ORACLE数据库系统是美国ORACLE公司 甲骨文 提供的以分布式数据库为核心的一组软件产品 是目前最流行的客户 服务器 CLIENT SERVER 或B S体系结构的数据库之一 比如SilverStream就是基于数据库的一种中间件 O
  • Linux系统的安装(在VM虚拟机上安装CentOS 7)

    工具准备 物理计算机一台 配置要求 操作系统 win10 64位 大家基本上都是 硬盘可用容量 20G以上 内存容量 4G以上 虚拟机安装包 VMware workstation full 12 5 下载链接 点我下载 提取码 9gha C
  • 计算机领域中随处可见的抽象

    想要管理多种具体的东西 那么需要遵守每种东西的规范 如果想要提供一种通用模式来对这些具体的东西统一管理 需要使用一种古老的技术 抽象 抽象是将多种具体的东西 管理时需要遵守的规范 的共同点抽取出来 放入到更高一层的抽象层 在抽象层不定义或少
  • unix环境高级编程——文件IO

    本期主题 unix环境高级编程 文件IO 文件IO 0 引言 1 文件描述符 2 IO编程中常用的API接口 1 open函数 2 close函数 3 read函数 4 write函数 5 lseek函数 3 函数sync fsync和fd
  • 操作系统学习(九)进程通信

    一 知识总览 二 定义 进程通信是指进程之间的信息交换 每个进程都拥有自己的内存空间 是相互独立的 这样在每个进程执行时 才不会被其他进程所干扰 三 进程通信的方式 1 共享存储 1 两个进程对共享区的访问必须是互斥的 即在同一时间内 只允
  • 虚拟机管理程序、虚拟化和云: 深入剖析 PowerVM 虚拟机管理程序

    预备知识 Power 是没有限制的虚拟化 一些企业打算依靠 PowerVM 虚拟化将多个工作负载整合到较少系统上 从而提高服务器利用率 降低成本 Power VM 为基于 Power Systems 平台的高级 RAS 功能和领先性能为 A
  • Linux 磁盘与文件系统管理(鸟哥私房菜)

    本文来自 http vbird dic ksu edu tw linux basic 0230filesystem php 第八章 Linux 磁盘与文件系统管理 系统管理员很重要的任务之一就是管理好自己的磁盘文件系统 每个分割槽不可太大也
  • Linux使用nvida-smi查看GPU类型

    nvida smi提供一个查看GPU信息的方法 然而这种方式不能查看GPU型号 型号被省略成了GeForce RTX 208 如果我们需要查看GPU的型号 只需要运行nvidia smi L即可 mrfive ubuntu nvidia s
  • 安装黑苹果双系统专辑贴(持续更新...)

    最近终于开始研究黑苹果 然后浏览了几篇文章贴收集一下 以便需要时随时阅览 和同学们互相学习 零基础篇 1 https blog csdn net a792396951 article details 80230946 2 https zhu
  • InfoQ视频直播分享报名:前贝尔实验室、Oracle架构师为你在线揭秘分布式平台内核...

    报名方式 关注InfoQ微信公众号 ID infoqchina 回复 InfoQ 即可观看在线直播技术分享 分享地点 u0026amp 时间 InfoQ直播微课堂将在熊猫 TV 网站播出 看腻了卖肉的女主播 来看看QCon 的明星讲师如何
  • 《一个操作系统的实现》读书笔记-- 第一章--最小的“操作系统”

    一 最简单的 操作系统 最最简单的 操作系统 就是一个最最简单的引导扇区 Boot Sector 虽然它不具有任何功能 但是它却能够直接在裸机上运行 不依赖其他软件 一个引导扇区是512个字节 并且以0xAA55为结束标识的扇区 下面就是那
  • 03LinuxC线程学习之线程共享和非共享

    1 线程共享和非共享 1 1 线程共享资源 1 文件描述符表 由于线程间共享进程间的内容 而文件描述符表在主线程的PCB当中 各个线程可以直接去请求访问 所以线程间通信就不需要像进程那样通过管道这些方式通信 2 每种信号的处理方式 即当某个
  • Windows运行常用命令(win+R)

    1 calc 启动计算器 2 notepad 打开记事本 3 write 写字板 4 mspaint 画图板 5 snippingtool 截图工具 支持无规则截图 6 mplayer2 简易widnows media player 7 S
  • Windows驱动开发(一)第一个驱动程序

    首先我们需要了解 在操作系统中 是分两种权限的 一种是内核态 我们也称为0环 一种是用户态 称之为3环 而在我们的电脑中 驱动程序是运行在内核态的 这意味着和操作系统内核是在同一权限的 而普通的应用程序的权限是最低的 高权限谁不想拥有呢 因
  • Linux常用命令记录

    文章目录 1 软件安装 安装软件 来自源服务器 安装 deb软件 来自本地 deb文件 修复依赖关系 卸载软件 2 文件 文件夹操作 删除文件夹 移动文件 文件重命名 3 程序查看 处理 进程查看 查看端口占用情况 强制终止程序 4 解压文
  • 内存管理——分页分段

    一 分页存储管理 1 页面与页框 1 页面 将一个进程的逻辑地址空间分成若干个大小相等的片 称为页面或页 并为各页加以编号 2 页框 相应于页面 把内存空间分成和页面相同大小的若干个存储块 称为 物理 块或页框 frame 3 页内碎片 在
  • MacOS中清除原有ssh公钥方法

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 用ssh的跳转登录服务器后 ssh会把你每个你访问过计算机的公钥 public key 都记录在 ssh known hosts 当下次访问相同计算机时 SSH会核对公钥
  • gdb attach 进程调试

    gdb调试正在运行的进程 GDB可以对正在执行的程序进行调度 它允许开发人员中断程序 并查看其状态 之后还能让这个程序正常地继续执行 gdb attach xxxxx xxxxx为利用ps命令获得的子进程process

随机推荐

  • 九轴姿态传感器的介绍和应用

    总体设计 姿态传感器是基于MEMS技术的高性能三维运动姿态测量系统 它包含三轴陀螺仪 三轴加速度计 xff0c 三轴电子罗盘等运动传感器 xff0c 通过内嵌的低功耗ARM处理器得到经过温度补偿的三维姿态与方位等数据 利用基于四元数的三维算
  • CAN总线简单介绍

    什么是CAN总线 xff1f Controller Area Network xff0c 简称CAN或者CAN bus 是一种功能丰富的串行总线标准 xff0c 最早的CAN控制芯片在奔驰车上应用并量产 xff0c 因为支持多主机 xff0
  • Ubuntu18.04 下realsense编译与安装

    相机型号 xff1a realsense SR300 系统环境 xff1a Ubuntu18 04 我这里是下载并编译源码的方式进行编译安装 具体编译安装可以参照https github com IntelRealSense libreal
  • Linux gvim 编辑器修改配色方案、字体、字号

    1 gvim相比于vim xff0c 目前知道gvim是可以单独窗口运行的 xff0c 像gedit一样 vim打开的文件貌似只能显示在终端内 但是二者安装的位置以及配置文件是很有联系的 xff0c 暂时的感觉是gvim是对vim的封装 x
  • 【路径规划】(3) RRT 算法求解最短路,附python完整代码

    大家好 xff0c 今天和各位分享一下机器人路径规划中的 RRT 算法 xff0c 感兴趣的点个关注 xff0c 文末有 python 代码 xff0c 那我们开始吧 1 算法介绍 RRT 算法是由学者 S M LaValle 提出来的路径
  • 【自动化测试】【安卓android】python 发送adb命令方法

    command 命令列表 xff0c 可以传入任意命令 xff0c 类型为list cmdMode可以选择发送命令方式为直接发送adb 命令还是先进入shell def sendAdbcmd command deviceID 61 34 3
  • 选择恐惧症的福音!教你认清MVC,MVP和MVVM

    相信大家对MVC xff0c MVP和MVVM都不陌生 xff0c 作为三个最耳熟能详的Android框架 xff0c 它们的应用可以是非常广泛的 xff0c 但是对于一些新手来说 xff0c 可能对于区分它们三个都有困难 xff0c 更别
  • FreeRtos嵌入式操作系统学习1--操作系统原理初探

    这里由于是第一篇文章 xff0c 不讲复杂的数据机构 xff0c 也不进行代码分析 xff0c 只讲嵌入式操作系统原理 先看下面一个简单的程序 xff1a void task1 while 1 Led1 1 xff08 1 xff09 de
  • 初学四旋翼之定高

    本项目使用US 100超声波模块测高 xff0c 与飞控的通讯方式为UART 硬件连接应注意 xff1a 通常飞控的发送管脚连超声波的接收管脚 xff0c 飞控的接收管脚连超声波的发送管脚 xff08 即tx rx xff1b rx tx
  • 初学四旋翼之光流定点

    本项目使用px4flow模块测速 xff0c 与飞控的通讯方式为I2C 安装时因注意光流模块与飞控的方向 xff08 一 xff09 为什么使用光流模块 xff1f 在悬停时 xff0c 若采用开环控制 xff0c 由于一些不可控的外界因素
  • 初学JetsonTX2之部署YOLO

    本人准备使用 YOLO进行人脸检测 xff0c 硬件设备为 Jetson TX2 查阅 YOLO 官网 xff0c 要部署 YOLO xff0c 首先要安装 CUDA CUDNN OPENCV xff0c 然后部署 Darknet xff0
  • C语言,超过10位数的字符串转整型函数

    include lt stdio h gt static long str2int const char str long temp 61 0 const char p 61 str if str 61 61 NULL return 0 i
  • C语言去掉MAC地址中的冒号

    include lt stdio h gt include lt string h gt void strdel char s char del x char p char q for p 61 s q 61 s p 61 39 0 39
  • Jetson Xavier NX 套件将系统装到SSD

    目录 第一步 xff1a 虚拟机 第二步 xff1a 装SDK Manager 第三步 xff1a 将系统装到eMMC 第四步 xff1a 将系统装到SSD内 xff0c 我以新买的500G硬盘为例 第五步 xff1a 装各种库 解决问题时
  • MySQL使用.ibd文件恢复或者迁移数据库

    使用86的Alice数据库的 ibd文件备份 恢复到76数据库 xff0c 该数据库版本为8 0 17 1 创建一个表确认与原始表结构一致 将86数据库的表结构导出 xff0c 在76上执行 xff08 注 xff1a 在5 5 26版本需
  • 学习ARM反汇编工具objdump和一个简单实例

    学习ARM反汇编工具objdump和一个简单实例 参考朱有鹏ARM裸机编程 1 反汇编的原理 amp 为什么需要反汇编 arm linux objdump D led elf gt led elf dis objdump是gcc工具链中的反
  • 从零开始学习UCOSII操作系统1--UCOSII的基础知识

    从零开始学习UCOSII操作系统1 UCOSII的基础知识 前言 xff1a 首先比较主流的操作系统有UCOSII FREERTOS LINUX等 xff0c UCOSII的资料相对比其余的两个操作系统的资料是多很多的 更重要的原因是自己本
  • 从零开始学习UCOSII操作系统2--UCOSII的内核实现

    从零开始学习UCOSII操作系统2 UCOSII的内核实现 参考书籍 xff1a 嵌入式实时操作系统 COS II原理及应用 嵌入式实时操作系统uCOS II 邵贝贝 第二版 1 任务的结构 任务控制块 首先这个任务控制块是非常的大的 xf
  • 从零开始学习UCOSII操作系统4--任务管理

    从零开始学习UCOSII操作系统4 任务管理 1 重讲任务 1 任务可以是一个无限的循环 xff0c 也可以在一次执行完毕后被删除 这里需要注意的是 xff0c 任务的代码并不是真正的删除了 xff0c 而是UCOSII不再理会该任务代码
  • 从零开始学习UCOSII操作系统7--信号量

    从零开始学习UCOSII操作系统7 信号量 参考博客 xff1a 64 http blog csdn net gatiemehttps blog csdn net gatieme article details 21071379 前言 xf