UCOSIII同时等待多个内核对象

前面讲述了UCOSIII的信号量(一个任务与另一个任务同步)、事件标志组(一个任务与多个任务同步),它们都可以完成任务的同步。同时,信号量(保证全局变量)、消息队列,它们都可以完成消息的传递。

但是,它们描述的情况都是任务如何等待单个对象,比如信号量、互斥信号量、消息队列和时间标志组等。本文我们就讲解一下UCOSIII如何同时等待多个内核对象,在UCOSIII中只支持同时等待多个信号量和消息队列,不支持同时等待多个事件标志组和互斥信号量。

UCOSIII中一个任务可以同时等待任意数量的信号量或者消息队列,当只要等到其中的任意一个的时候就会导致该任务进入就绪态,如下图所示:

需要注意:在事件标志组中,用户可以自主设定究竟是等待多个任务同时置1还是同时清零,或者是只要有置1,只要有清零多种情况下的任务同步。但是在UCOSIII同时等待多个内核对象的情况下,只能等到任何一个信号量或者消息队列就被同步,进入就绪态。只有这一种情况。

UCOSIII同时等待多个内核对象API函数

首先需要注意的是:同时等待多个内核对象并不需要和之前的信号量、消息队列、事件标志组一样,先声明一个对象,在通过xxxCreate()函数定义出来……它只有一个函数,直接用的函数!

OSPendMulti()函数

函数OSPendMulti()用来等待多个内核对象,调用OSPendMulti()时,如果这些对象中有多个可用,则所有可用的信号量和消息都将返回给调用者;如果没有任何对象可用,则OSPendMulti()将挂起当前任务,直到以下任一情况发生:

  • 对象变为可用;
  • 到达设定的超时时间;
  • 一个或多个任务被删除或被终止;
  • 一个或多个对象被删除。

如果一个对象变为可用,并且有多个任务在等待这个对象,则UCOSIII将恢复优先级最高的那个任务函数OSPendMulti()原型如下:

OS_OBJ_QTY  OSPendMulti (OS_PEND_DATA  *p_pend_data_tbl,                //指向OS_PEND_DATA表的指针OS_OBJ_QTY     tbl_size,                    //所等待的内核对象数量OS_TICK        timeout,                        //设定一个等待超时值(时钟节拍数)OS_OPT         opt,                            //来选择是否使用阻塞模式OS_ERR        *p_err)
{CPU_BOOLEAN   valid;OS_OBJ_QTY    nbr_obj_rdy;CPU_SR_ALLOC();valid = OS_PendMultiValidate(p_pend_data_tbl,           /* -------- Validate objects to be OS_SEM or OS_Q ------- */tbl_size);if (valid == DEF_FALSE) {*p_err = OS_ERR_OBJ_TYPE;                            /* Invalid, not OS_SEM or OS_Q                            */return ((OS_OBJ_QTY)0);}CPU_CRITICAL_ENTER();nbr_obj_rdy = OS_PendMultiGetRdy(p_pend_data_tbl,       /* --------- SEE IF OBJECT(s) HAVE BEEN POSTED ---------- */tbl_size);if (nbr_obj_rdy > (OS_OBJ_QTY)0) {CPU_CRITICAL_EXIT();*p_err = OS_ERR_NONE;return ((OS_OBJ_QTY)nbr_obj_rdy);}if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) {    /* Caller wants to block if not available?                */CPU_CRITICAL_EXIT();*p_err = OS_ERR_PEND_WOULD_BLOCK;                    /* No                                                     */return ((OS_OBJ_QTY)0);} else {if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {    /* Can't pend when the scheduler is locked                */CPU_CRITICAL_EXIT();*p_err = OS_ERR_SCHED_LOCKED;return ((OS_OBJ_QTY)0);}}OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();                  /* Lock the scheduler/re-enable interrupts                *//* ------ NO OBJECT READY, PEND ON MULTIPLE OBJECTS ----- */OS_PendMultiWait(p_pend_data_tbl,                       /* Suspend task until object posted or timeout occurs     */tbl_size,timeout);OS_CRITICAL_EXIT_NO_SCHED();OSSched();                                              /* Find next highest priority task ready                  */CPU_CRITICAL_ENTER();switch (OSTCBCurPtr->PendStatus) {case OS_STATUS_PEND_OK:                             /* We got one of the objects posted to                    */*p_err = OS_ERR_NONE;break;case OS_STATUS_PEND_ABORT:                          /* Indicate that the multi-pend was aborted               */*p_err = OS_ERR_PEND_ABORT;break;case OS_STATUS_PEND_TIMEOUT:                        /* Indicate that we didn't get semaphore within timeout   */*p_err = OS_ERR_TIMEOUT;break;case OS_STATUS_PEND_DEL:                            /* Indicate that an object pended on has been deleted     */*p_err = OS_ERR_OBJ_DEL;break;default:*p_err = OS_ERR_STATUS_INVALID;break;}OSTCBCurPtr->PendStatus = OS_STATUS_PEND_OK;CPU_CRITICAL_EXIT();return ((OS_OBJ_QTY)1);
}

p_pend_data_tbl:指向OS_PEND_DATA表的指针,调用者通过该表来查询函数的调用结果。调用该函数的时候首先必须初始化OS_PEND_DATA表中的每个元素的PendObjPtr,使得各个指针指向被等待的对象。

tbl_siae:表p_pend_data_tbl的大小,也就是所等待的内核对象数量。

timeout:设定一个等待超时值(时钟节拍数),用来设置任务等待对象发送的时间,如果为0,表示这个任务将一直等待下去,直到对象被发送。

opt:来选择是否使用阻塞模式,有两个选项可以选择。OS_OPT_PEND_BLOCKING:如果没有任何消息存在的话就阻塞任务,一直等待,直到接收到消息;OS_OPT_PEND_NON_BLOCKING:如果消息队列没有任何消息的话任务就直接返回。

本函数的返回值为等待的多个内核对象中哪些是可用的。

OS_PEND_DATA

虽然我们不需要定义一个同时等待多个内核对象,但是我们需要定义一个数组,用来将需要等待的内核对象放入其中:也就是OS_PEND_DATA类型的数组:

struct  os_pend_data {OS_PEND_DATA        *PrevPtr;OS_PEND_DATA        *NextPtr;OS_TCB              *TCBPtr;OS_PEND_OBJ         *PendObjPtr;            //指向需要等待的内核对象OS_PEND_OBJ         *RdyObjPtr;void                *RdyMsgPtr;OS_MSG_SIZE          RdyMsgSize;CPU_TS               RdyTS;
};

在这个结构体中,PendObjPtr就是指向需要等待的内核对象。所以,我们需要定义一个OS_PEND_DATA类型的数组,再向每个数组元素的PendObjPtr成员对象赋需要等待的内核对象的地址。比如:

OS_SEM   Test_Sem1;          //信号量1
OS_SEM  Test_Sem2;          //信号量2
OS_Q    Test_Q;             //消息队列OS_PEND_DATA pend_multi_tbl[CORE_OBJ_NUM];      //定义数组
pend_multi_tbl[0].PendObjPtr=(OS_PEND_OBJ*)&Test_Sem1;
pend_multi_tbl[1].PendObjPtr=(OS_PEND_OBJ*)&Test_Sem2;
pend_multi_tbl[2].PendObjPtr=(OS_PEND_OBJ*)&Test_Q;

UCOSIII实际例程

同时等待多个内核对象

例程要求:设计一个应用程序,该程序有3任务、2个信号量和1个消息队列。任务A用于创建其他2个任务、2个信号量和1个消息队列。B任务为任务1,用于检测按键,当检测到按键KEY1被按下就发送信号量1,当KEY2被按下就发送信号量2,当KEY_UP被按下就发送消息队列,任务1还用来控制LED0的闪烁。任务C调用函数OSPendMulti()来同时等待2个信号量和1个消息队列。

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "key.h"
#include "sram.h"
#include "malloc.h"
#include "includes.h"//UCOSIII中以下优先级用户程序不能使用,ALIENTEK
//将这些优先级分配给了UCOSIII的5个系统内部任务
//优先级0:中断服务服务管理任务 OS_IntQTask()
//优先级1:时钟节拍任务 OS_TickTask()
//优先级2:定时任务 OS_TmrTask()
//优先级OS_CFG_PRIO_MAX-2:统计任务 OS_StatTask()
//优先级OS_CFG_PRIO_MAX-1:空闲任务 OS_IdleTask()//任务优先级
#define START_TASK_PRIO     3
//任务堆栈大小
#define START_STK_SIZE      128
//任务控制块
OS_TCB StartTaskTCB;
//任务堆栈
CPU_STK START_TASK_STK[START_STK_SIZE];
//任务函数
void start_task(void *p_arg);//任务优先级
#define TASK1_TASK_PRIO     4
//任务堆栈大小
#define TASK1_STK_SIZE      128
//任务控制块
OS_TCB Task1_TaskTCB;
//任务堆栈
CPU_STK TASK1_TASK_STK[TASK1_STK_SIZE];
void task1_task(void *p_arg);//任务优先级
#define TASK2_TASK_PRIO     5
//任务堆栈大小
#define TASK2_STK_SIZE      128
//任务控制块
OS_TCB Task2_TaskTCB;
//任务堆栈
CPU_STK TASK2_TASK_STK[TASK2_STK_SIZE];
void task2_task(void *p_arg);//任务优先级
#define MULTI_TASK_PRIO     6
//任务堆栈大小
#define MULTI_STK_SIZE      128
//任务控制块
OS_TCB Multi_TaskTCB;
//任务堆栈
CPU_STK MULTI_TASK_STK[MULTI_STK_SIZE];
void multi_task(void *p_arg);//LCD刷屏时使用的颜色
int lcd_discolor[14]={ WHITE, BLACK, BLUE,  BRED,      GRED,  GBLUE, RED,   MAGENTA,            GREEN, CYAN,  YELLOW,BROWN,            BRRED, GRAY };OS_SEM    Test_Sem1;          //信号量1
OS_SEM  Test_Sem2;          //信号量2
OS_Q    Test_Q;             //消息队列
#define QUEUE_NUM       10  //消息队列长度
#define CORE_OBJ_NUM    3   //内核对象个数,一共3个:2个信号量和一个消息队列                                            int main(void)                        //主函数
{OS_ERR err;CPU_SR_ALLOC();delay_init();    //时钟初始化NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组配置uart_init(115200);  //串口初始化LED_Init();         //LED初始化   LCD_Init();         //LCD初始化    KEY_Init();         //按键初始化FSMC_SRAM_Init();    //初始化SRAMmy_mem_init(SRAMIN);//初始化内部RAMPOINT_COLOR = RED;LCD_ShowString(30,10,200,16,16,"ALIENTEK STM32F1"); LCD_ShowString(30,30,200,16,16,"UCOSIII Examp 13-1");LCD_ShowString(30,50,200,16,16,"Pend Multi");LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");LCD_ShowString(30,90,200,16,16,"2015/5/20");POINT_COLOR = BLACK;LCD_DrawRectangle(5,110,234,314);   LCD_DrawLine(5,130,234,130);POINT_COLOR = RED;LCD_ShowString(50,111,200,16,16,"ObjRdy_NUM: 0");POINT_COLOR = BLUE;OSInit(&err);             //初始化UCOSIIIOS_CRITICAL_ENTER();    //进入临界区          //创建开始任务OSTaskCreate((OS_TCB   * )&StartTaskTCB,       //任务控制块(CPU_CHAR    * )"start task",      //任务名字(OS_TASK_PTR )start_task,             //任务函数(void     * )0,                   //传递给任务函数的参数(OS_PRIO      )START_TASK_PRIO,     //任务优先级(CPU_STK   * )&START_TASK_STK[0],    //任务堆栈基地址(CPU_STK_SIZE)START_STK_SIZE/10,   //任务堆栈深度限位(CPU_STK_SIZE)START_STK_SIZE,     //任务堆栈大小(OS_MSG_QTY  )0,                    //任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息(OS_TICK   )0,                   //当使能时间片轮转时的时间片长度,为0时为默认长度,(void      * )0,                   //用户补充的存储区(OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项(OS_ERR  * )&err);               //存放该函数错误时的返回值OS_CRITICAL_EXIT();   //退出临界区  OSStart(&err);      //开启UCOSIII
}void start_task(void *p_arg)                    //开始任务函数
{OS_ERR err;CPU_SR_ALLOC();p_arg = p_arg;CPU_Init();
#if OS_CFG_STAT_TASK_EN > 0uOSStatTaskCPUUsageInit(&err);    //统计任务
#endif#ifdef CPU_CFG_INT_DIS_MEAS_EN        //如果使能了测量中断关闭时间CPU_IntDisMeasMaxCurReset();
#endif#if   OS_CFG_SCHED_ROUND_ROBIN_EN  //当使用时间片轮转的时候//使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5msOSSchedRoundRobinCfg(DEF_ENABLED,1,&err);
#endif  OS_CRITICAL_ENTER();    //进入临界区OSSemCreate ((OS_SEM*    )&Test_Sem1,                //创建信号量Test_Sem1(CPU_CHAR*  )"Test_Sem1",(OS_SEM_CTR)0,       (OS_ERR*    )&err);OSSemCreate ((OS_SEM*    )&Test_Sem2,                //创建信号量Test_Sem2(CPU_CHAR*  )"Test_Sem2",(OS_SEM_CTR)0,       (OS_ERR*    )&err);//创建消息队列OSQCreate ((OS_Q*        )&Test_Q,   //消息队列(CPU_CHAR*    )"KEY Msg",   //消息队列名称(OS_MSG_QTY )QUEUE_NUM, //消息队列长度(OS_ERR*    )&err);     //错误码OSTaskCreate((OS_TCB   * )&Task1_TaskTCB,                  //创建TASK1任务(CPU_CHAR    * )"Task1 task",      (OS_TASK_PTR )task1_task,           (void       * )0,                   (OS_PRIO      )TASK1_TASK_PRIO,     (CPU_STK   * )&TASK1_TASK_STK[0],   (CPU_STK_SIZE)TASK1_STK_SIZE/10,    (CPU_STK_SIZE)TASK1_STK_SIZE,       (OS_MSG_QTY  )0,                    (OS_TICK      )0,                   (void       * )0,                   (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,(OS_ERR   * )&err);               OSTaskCreate((OS_TCB    * )&Multi_TaskTCB,          //创建MULTI测试任务(CPU_CHAR  * )"Multi task",      (OS_TASK_PTR )multi_task,           (void       * )0,                   (OS_PRIO      )MULTI_TASK_PRIO,     (CPU_STK   * )&MULTI_TASK_STK[0],   (CPU_STK_SIZE)MULTI_STK_SIZE/10,    (CPU_STK_SIZE)MULTI_STK_SIZE,       (OS_MSG_QTY  )0,                    (OS_TICK      )0,                   (void       * )0,                   (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,(OS_ERR   * )&err);   OS_CRITICAL_EXIT(); //退出临界区OSTaskDel((OS_TCB*)0,&err);  //删除start_task任务自身
}void task1_task(void *p_arg)            //任务1的任务函数
{u8 key;OS_ERR err;u8 num;u8 *pbuf;static u8 msg_num;pbuf=mymalloc(SRAMIN,10); //申请内存while(1){key = KEY_Scan(0);  //扫描按键switch(key){case KEY1_PRES:OSSemPost(&Test_Sem1,OS_OPT_POST_1,&err);//发送信号量1break;case KEY0_PRES:OSSemPost(&Test_Sem2,OS_OPT_POST_1,&err);//发送信号量2case WKUP_PRES:msg_num++;sprintf((char*)pbuf,"ALIENTEK %d",msg_num);//发送消息OSQPost((OS_Q*        )&Test_Q,       (void*      )pbuf,(OS_MSG_SIZE)10,(OS_OPT       )OS_OPT_POST_FIFO,(OS_ERR*  )&err);break;}num++;if(num==50){num=0;LED0=~LED0;}OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_PERIODIC,&err);   //延时10ms}
}void multi_task(void *p_arg)                    //等待多个内核对象的任务函数
{   u8 num;OS_ERR err;OS_OBJ_QTY index;OS_PEND_DATA pend_multi_tbl[CORE_OBJ_NUM];   pend_multi_tbl[0].PendObjPtr=(OS_PEND_OBJ*)&Test_Sem1;pend_multi_tbl[1].PendObjPtr=(OS_PEND_OBJ*)&Test_Sem2;pend_multi_tbl[2].PendObjPtr=(OS_PEND_OBJ*)&Test_Q;while(1){index=OSPendMulti((OS_PEND_DATA*    )pend_multi_tbl,    (OS_OBJ_QTY     )CORE_OBJ_NUM,  //内核数量(OS_TICK          )0,     (OS_OPT             )OS_OPT_PEND_BLOCKING,(OS_ERR*          )&err);LCD_ShowNum(147,111,index,1,16);                     //显示当前有几个内核对象准备好了num++;LCD_Fill(6,131,233,313,lcd_discolor[num%14]);      //刷屏LED1 = ~LED1;OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   //延时1s}
}//创建信号量Test_Sem1(CPU_CHAR* )"Test_Sem1",(OS_SEM_CTR)0,       (OS_ERR*    )&err);OSSemCreate ((OS_SEM*    )&Test_Sem2,                //创建信号量Test_Sem2(CPU_CHAR*  )"Test_Sem2",(OS_SEM_CTR)0,       (OS_ERR*    )&err);//创建消息队列OSQCreate ((OS_Q*        )&Test_Q,   //消息队列(CPU_CHAR*    )"KEY Msg",   //消息队列名称(OS_MSG_QTY )QUEUE_NUM, //消息队列长度(OS_ERR*    )&err);     //错误码OSTaskCreate((OS_TCB   * )&Task1_TaskTCB,                  //创建TASK1任务(CPU_CHAR    * )"Task1 task",      (OS_TASK_PTR )task1_task,           (void       * )0,                   (OS_PRIO      )TASK1_TASK_PRIO,     (CPU_STK   * )&TASK1_TASK_STK[0],   (CPU_STK_SIZE)TASK1_STK_SIZE/10,    (CPU_STK_SIZE)TASK1_STK_SIZE,       (OS_MSG_QTY  )0,                    (OS_TICK      )0,                   (void       * )0,                   (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,(OS_ERR   * )&err);               OSTaskCreate((OS_TCB    * )&Multi_TaskTCB,          //创建MULTI测试任务(CPU_CHAR  * )"Multi task",      (OS_TASK_PTR )multi_task,           (void       * )0,                   (OS_PRIO      )MULTI_TASK_PRIO,     (CPU_STK   * )&MULTI_TASK_STK[0],   (CPU_STK_SIZE)MULTI_STK_SIZE/10,    (CPU_STK_SIZE)MULTI_STK_SIZE,       (OS_MSG_QTY  )0,                    (OS_TICK      )0,                   (void       * )0,                   (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,(OS_ERR   * )&err);   OS_CRITICAL_EXIT(); //退出临界区OSTaskDel((OS_TCB*)0,&err);  //删除start_task任务自身
}void task1_task(void *p_arg)            //任务1的任务函数
{u8 key;OS_ERR err;u8 num;u8 *pbuf;static u8 msg_num;pbuf=mymalloc(SRAMIN,10); //申请内存while(1){key = KEY_Scan(0);  //扫描按键switch(key){case KEY1_PRES:OSSemPost(&Test_Sem1,OS_OPT_POST_1,&err);//发送信号量1break;case KEY0_PRES:OSSemPost(&Test_Sem2,OS_OPT_POST_1,&err);//发送信号量2case WKUP_PRES:msg_num++;sprintf((char*)pbuf,"ALIENTEK %d",msg_num);//发送消息OSQPost((OS_Q*        )&Test_Q,       (void*      )pbuf,(OS_MSG_SIZE)10,(OS_OPT       )OS_OPT_POST_FIFO,(OS_ERR*  )&err);break;}num++;if(num==50){num=0;LED0=~LED0;}OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_PERIODIC,&err);   //延时10ms}
}void multi_task(void *p_arg)                    //等待多个内核对象的任务函数
{   u8 num;OS_ERR err;OS_OBJ_QTY index;OS_PEND_DATA pend_multi_tbl[CORE_OBJ_NUM];   pend_multi_tbl[0].PendObjPtr=(OS_PEND_OBJ*)&Test_Sem1;pend_multi_tbl[1].PendObjPtr=(OS_PEND_OBJ*)&Test_Sem2;pend_multi_tbl[2].PendObjPtr=(OS_PEND_OBJ*)&Test_Q;while(1){index=OSPendMulti((OS_PEND_DATA*    )pend_multi_tbl,    (OS_OBJ_QTY     )CORE_OBJ_NUM,  //内核数量(OS_TICK          )0,     (OS_OPT             )OS_OPT_PEND_BLOCKING,(OS_ERR*          )&err);LCD_ShowNum(147,111,index,1,16);                     //显示当前有几个内核对象准备好了num++;LCD_Fill(6,131,233,313,lcd_discolor[num%14]);      //刷屏LED1 = ~LED1;OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   //延时1s}
}

【UCOSIII】UCOSIII的同时等待多个内核对象相关推荐

  1. uCOS-III学习笔记(10)----等待多个内核对象

    理解:等待多个内核对象说的就是,比如一个任务需要等待信号量才能打开led1,等待一个消息队列才能打开led2,此时不用等待多个内核对象的话就算来了信号量也会被pend卡住而不能往下面运行,所以等待多个 ...

  2. μC/OS-III---I笔记9---任务等待多个内核对象和任务内建信号量与消息队列

    在一个任务等待多个内核对象在之前,信号量和消息队列的发布过程中都有等待多个内核对象判断的函数,所谓任务等待多个内核对象顾名思义就是一任务同时等待多个内核对象而被挂起,在USOC-III中一个任务等待多 ...

  3. STM32工作笔记0088---时间标志组和同时等待多个内核对象

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 两个任务之间的同步,咱们一般用信号量,但是 一个任务和多个事件之间的同步可以用或同步,和 与同步.

  4. Windows核心编程 第九章 线程与内核对象的同步(下)

    9.4 等待定时器内核对象 等待定时器是在某个时间或按规定的间隔时间发出自己的信号通知的内核对象.它们通常用来在某个时间执行某个操作. 若要创建等待定时器,只需要调用C r e a t e Wa i ...

  5. 第九章 线程与内核对象的同步(6)

    六.其他的线程同步函数 1.异步设备I/O 异步设备I/O使得线程能够启动一个读操作或写操作,但是不必等待读操作或写操作完成.设备对象是可以同步的内核对象,可以调用WaitForSingleObjec ...

  6. 线程与内核对象的同步——Windows核心编程学习手札之九

    线程与内核对象的同步 --Windows核心编程学习手札之九 用户方式下的线程同步机制具有速度快的特点,但有其局限性,对于许多应用程序来说,并不合适.例如,互锁函数家族只能在单值上运行,根本无法使线程 ...

  7. 用内核对象进行线程同步

    本章讨论的是如何使用内核对象来对线程进行同步,与用户模式下的同步机制相比,内核对象的用途要广泛的多.实际上,内核对象唯一的缺点就是他们的性能.当我们调用本章任何一个新函数时,调用线程必须从用户模式切换 ...

  8. Windows核心编程:第9章 用内核对象进行线程同步

    Github https://github.com/gongluck/Windows-Core-Program.git //第9章 用内核对象进行线程同步.cpp: 定义应用程序的入口点. //#in ...

  9. Windows核心编程学习九:利用内核对象进行线程同步

    注:源码为学习<Windows核心编程>的一些尝试,非原创.若能有助于一二访客,幸甚. 1.程序框架 #include "Queue.h" #include <t ...

最新文章

  1. C语言从文件中读入矩阵,并且将矩阵转置
  2. ES6学习笔记(五):轻松了解ES6的内置扩展对象
  3. 启动mysq服务_mysql安装、启动
  4. 怎么拆除境地柜_内衣不合身拒绝接亲,精装房装修不满意怎么办?
  5. 软件_crontab任务配置失败原因总结和技巧
  6. 涂鸦蓝牙SDK开发系列教程——4.烧录授权
  7. 永宏plc和台达vfd-m变頻器modbs rtu通讯程序 史上最好用的plc和变頻器rtu通讯程序
  8. linux rarcrack破解rar、zip和7z压缩包简单密码的工具
  9. 基于Java、MySQL的毕业设计,房屋租赁系统
  10. /usr/bin/ld cannot find -lGL
  11. 树莓派配置记录——aria2
  12. ORACLE OCP 考试指南
  13. 血管内冲击波:冠状动脉钙化处理的技术革新
  14. c# lu分解的代码_LU分解法(C语言)
  15. Edge主页被360篡改的解决办法
  16. 计算机告诉你,唐朝诗人之间的关系到底是什么样的?
  17. linux刷新本地dns命令_在Linux/Windows/Mac上刷新DNS缓存的方法
  18. pythonmt4通讯swot矩阵_SWOT矩阵表
  19. linux网络服务详解,Linux网络服务器配置基础详解 (3)
  20. 3DM视觉测量技术的应用及发展

热门文章

  1. Python - 一种一次性导出或修改所有类对象属性与值的方法
  2. 微信小程序校园社团管理系统项目源码来了~
  3. greenplum的几个内存配置
  4. VUE 输入框disabled颜色问题解决
  5. python——socket编程
  6. Ubuntu16.04+GeForce GTX 1070Ti+CUDA8.0+cuDNN6.0+TensorFlow1.3+tf-faster-rcnn训练
  7. 基于JAVAWEB的私人牙科诊所管理系统
  8. Android zxing扫码截彩色图
  9. 通过MOGRT(基本图形)实现AE与PR模板通用
  10. 水果店坏果处理,水果店卖不完如何处理