精华内容
下载资源
问答
  • 概述信号量VxWorks任务间进行通信、同步和互斥的最优选择,提供任务间最快速的通信。也是提供任务间同步和互斥的主要手段。注意vxworks提供二进制信号量、互斥信号量、计数信号量、读写...

    概述

    信号量是VxWorks任务间进行通信、同步和互斥的最优选择,提供任务间最快速的通信。也是提供任务间同步和互斥的主要手段。

    注意

    vxworks提供二进制信号量、互斥信号量、计数信号量、读写信号量4种类型的信号量。

    二进制信号量:主要用于任务同步,相当于 0和1,所有任务均可通过 semGive()释放,其余任务通过semTake()获取,同一时刻只能有一个semTake()获取到,具体机制看基于SEM_Q_PRIORITY还是SEM_Q_FIFO,只有获取到的任务释放后,下一个任务才能获取到。

    互斥信号量:是一种特殊的二进制信号量,主要用于解决二进制信号量内在的互斥问题如优先级继承、删除安全和递归等情况。同一时刻也只能一个任务获取到信号量,但是允许同一个任务多次获取同一个信号量,这时,获取和释放操作必须一一对应,即semTake()和semGive()成对出现,同时,只能由拥有信号量的任务才能释放信号量。

    计数信号量:信号量可以被多个任务获取,主要取决于信号量的计数值,主要用于 多次同时访问能力的资源。

    读写信号量:不常用。

    另外,小编所有文章均是自己亲手编写验证,若需要小编的工程代码,请关注公众号,后台回复需要的工程文件如想要本文中的工程源文件可回复“实时系统vxWorks - 信号量工程文件”获取。

    接口

    官方接口

    官方sem接口定义主要包含在semLibCommon.h和semLib.h头文件中。

    重要定义

    #define SEM_ID_NULL ((SEM_ID) 0)    /* 信号量ID为空 */
    
    #define SEM_Q_FIFO      0x00        /* 按照先进先出的方式获取信号量 */
    #define SEM_Q_PRIORITY  0x01        /* 按照优先级方式获取信号量 */
    #define SEM_DELETE_SAFE 0x04        /* 删除保护,防止意外删除 */
    #define SEM_INVERSION_SAFE 0x08     /* no priority inversion (mutex opt.) */
    #define SEM_EVENTSEND_ERR_NOTIFY 0x10    /* notify when eventRsrcSend fails */
    #define SEM_INTERRUPTIBLE 0x20      /* interruptible on RTP signal */
    
    /* 信号量类型 */
    typedef enum  {
        SEM_TYPE_BINARY,    /* 0: 二进制信号量 */
        SEM_TYPE_MUTEX,     /* 1: 互斥信号量 */
        SEM_TYPE_COUNTING,  /* 2: 计数信号量 */
        SEM_TYPE_RW,        /* 3: 读写信号量,很少用 */
        /*
         * Reduce SEM_TYPE_MAX for small footprint, which allows only the
         * above 4 types, to eliminate wasted space in semaphore tables.
         */
    #ifndef    _WRS_CONFIG_CUSTOM_SEMAPHORE_TYPES     
        SEM_TYPE_MAX = 4
    #else    /* _WRS_CONFIG_CUSTOM_SEMAPHORE_TYPES */
        SEM_TYPE_MAX = 8    
    #endif    /* _WRS_CONFIG_CUSTOM_SEMAPHORE_TYPES */
    } SEM_TYPE;
    
    /* 二进制信号量状态 */
    typedef enum {
        SEM_EMPTY,   /* 0: 不可用 */
        SEM_FULL     /* 1: 可用 */
    } SEM_B_STATE;
    

    创建/删除信号量

    /**
     * @创建信号量,semMCreate互斥信号量,semBCreate二进制信号量,semCCreate计数信号量,semRWCreate读写信号量
     * @options: 选项   initialState:初始二进制状态    initialCount:初始计数量
     * @成功返回信号量ID,失败返回SEM_ID_NULL。
     */
    extern SEM_ID semMCreate(int options);
    extern SEM_ID semBCreate(int options, SEM_B_STATE initialState);
    extern SEM_ID semCCreate(int options, int initialCount);
    extern SEM_ID semRWCreate(int options, int maxReaders);
    
    /**
     * @删除信号量
     * @semId: 信号量ID   
     * @成功返回OK,失败返回ERROR。
     */
    extern STATUS semDelete(SEM_ID semId);
    

    获取/释放信号量

    /**
     * @释放信号量
     * @semId: 信号量ID   
     * @成功返回OK,失败返回ERROR。
     */
    extern STATUS semGive(SEM_ID semId);
    /**
     * @获取信号量
     * @semId: 信号量ID     timeout:指定超时时间  WAIT_FOREVER(-1)表示死等和NO_WAIT(0)表示不等待     
     * @成功返回OK,失败返回ERROR。
     */
    extern STATUS semTake(SEM_ID semId, _Vx_ticks_t timeout);
    /**
     * @解锁所有阻塞在信号量上的任务,一般在同步信号量中用于类似广播的场景,在互斥信号量中属于非法操作
     * @semId: 信号量ID   
     * @成功返回OK,失败返回ERROR。
     */
    extern STATUS semFlush(SEM_ID semId);
    

    查看信号量信息

    /**
     * @初始化信号量显示模块  
     */
    extern void semShowInit(void);
    /**
     * @显示信号量信息,用于显示信号量的状态以及被阻塞的任务
     * @semId: 信号量ID     level:0-显示摘要,1-显示详情    
     * @成功返回OK,失败返回ERROR。
     */
    extern STATUS semShow(SEM_ID semId, int level);
    /**
     * @获取阻塞在信号量上的任务列表
     * @semId: 信号量ID     idList:任务ID数组  maxTasks:最大任务数
     * @放置在idList中阻塞任务的个数
     */
    extern int semInfo(SEM_ID semId, TASK_ID idList[], int maxTasks);
    

    信号量对象接口

    属性定义

    #define MAX_SEM_NUM         40  /* 系统最大信号量数 */
    #define MAX_SEM_NAME_LEN    24  /* 信号名最大长度 */
    
    /* 信号量类型 */
    typedef enum e_semType
    {
        SEM_BIN     = 0,            /* 二进制信号量类型 */
        SEM_MUTEX   = 1,            /* 互斥信号量类型 */
    }E_SEM_TYPE;
    
    /* 信号量基类信息 */
    struct t_sem{
        E_SEM_TYPE     type;       /* 信号类型, SEM_BIN, SEM_MUTEX */
        SEM_ID         sem;        /* 信号量 */
        int            period;     /* 任务运行周期 */
        unsigned int   preHeart;   /* 上一拍心跳 */
        unsigned int   currHeart;  /* 当前心跳 */
        char           name[MAX_SEM_NAME_LEN]; /* 信号名 */   
    };
    
    /* 信号量类集合定义 */
    struct sem {
        s32_t num;                          /* 信号量数 */
        struct t_sem info[MAX_SEM_NUM];     /* 系统信号量信息 */   
    };
    

    获取/释放信号量

    /**
     * @通过信号量名获取信号量
     * @p_sem:信号量类集合        name: 信号量名
     **/
    void get_sem_by_name(struct sem *p_sem, char *name);
    
    /**
     * @通过信号量名释放信号量
     * @p_sem:信号量类集合        name: 信号量名
     **/
    void lose_sem_by_name(struct sem *p_sem, char *name);
    
    /**
     * @获取信号量
     * @p_sem:信号量类
     **/
    void get_sem(struct t_sem *p_sem);
    
    /**
     * @释放信号量
     * @p_sem:信号量类
     **/
    void lose_sem(struct t_sem *p_sem);
    

    周期信号量操作

    /**
     * @同步信号量释放
     * @p_sem:信号量类集合    time:定时器时间
     **/
    void lose_sync_sem(struct sem *p_sem, u64_t time);
    
    /**
     * @设置指定信号量周期
     * @p_sem:信号量类集合        name:信号量名       period:周期
     **/
    void set_sem_period(struct sem *p_sem, s8_t *name, s32_t period);
    

    注册、创建信号量

    /**
     * @信号量注册
     * @p_sem:信号量类集合        p_info:加入信号量信息
     **/
    void resgister_sem(struct sem *p_sem, struct t_sem *p_info);
    
    /**
     * @创建信号量类
     * @p_sem:信号量类        src:源信号量类       dst:目的信号量类
     **/
    void new_sem(struct sem *p_sem, struct t_sem *src, struct t_sem *dst);
    

    显示信号量信息

    /**
     * @显示指定信号量信息
     * @p_sem:信号量类        name:信号量名       level:0-显示摘要,1-显示详情    
    **/
    void show_sem_info(struct sem *p_sem, char *name, int level);
    

    示例

    ★示例通过操作二进制信号量实现任务同步。

    ★包含信号量类sem.c/sem.h及演示程序main.c(已验证通过)。

     sem.h

    /**
     * @Filename : sem.h
     * @Revision : $Revision: 1.00 $
     * @Author : Feng(更多编程相关的知识和源码见微信公众号:不只会拍照的程序猿,欢迎订阅)
     * @Description : 信号量类
    **/
    
    #ifndef __SEM_CLASS_H__
    #define __SEM_CLASS_H__
    
    #include <vxWorks.h>    
    #include <math.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include "semLib.h" 
    #include "feng_type.h"
    
    #define MAX_SEM_NUM         40  /* 系统最大信号量数 */
    #define MAX_SEM_NAME_LEN    24  /* 信号名最大长度 */
    
    /* 信号量类型 */
    typedef enum e_semType
    {
        SEM_BIN     = 0,           /* 二进制信号量类型 */
        SEM_MUTEX   = 1,           /* 互斥信号量类型 */
    }E_SEM_TYPE;
    
    /* 信号量基类信息 */
    struct t_sem{
        E_SEM_TYPE      type;       /* 信号类型, SEM_BIN, SEM_MUTEX */
        SEM_ID          sem;        /* 信号量 */
        int             period;     /* 任务运行周期 */
        unsigned int    preHeart;   /* 上一拍心跳 */
        unsigned int    currHeart;  /* 当前心跳 */
        char            name[MAX_SEM_NAME_LEN]; /* 信号名 */   
    };
    
    /* 信号量类集合定义 */
    struct sem {
        s32_t num;   /* 信号量数 */
        struct t_sem info[MAX_SEM_NUM];     /* 系统信号量信息 */   
    };
    
    /* 信号量注册 */
    void resgister_sem(struct sem *p_sem, struct t_sem *p_info);
    
    /* 通过信号量名获取信号量 */
    void get_sem_by_name(struct sem *p_sem, char *name);
    
    /* 通过信号量名释放信号量 */
    void lose_sem_by_name(struct sem *p_sem, char *name);
    
    /* 获取信号量 */
    void get_sem(struct t_sem *p_sem);
    
    /* 释放信号量 */
    void lose_sem(struct t_sem *p_sem);
    
    /* 同步信号量释放 */
    void lose_sync_sem(struct sem *p_sem, u64_t time);
    
    /* 设置指定信号量周期 */
    void set_sem_period(struct sem *p_sem, s8_t *name, s32_t period);
    
    /* 创建信号量类 */
    void new_sem(struct sem *p_sem, struct t_sem *src, struct t_sem *dst);
    
    /**
     * @显示指定信号量信息
     * @p_sem:信号量类        name:信号量名       level:0-显示摘要,1-显示详情    
    **/
    void show_sem_info(struct sem *p_sem, char *name, int level);
    
    #endif
    

     sem.c

    /**
     * @Filename : sem.c
     * @Revision : $Revision: 1.00 $
     * @Author : Feng(更多编程相关的知识和源码见微信公众号:不只会拍照的程序猿,欢迎订阅)
     * @Description : 信号量类
    **/
    
    #include "sem.h"
    #include <logLib.h>
    
    /**
     * @创建信号量
     * @p_sem:信号量类
     * @成功返回OK, 失败返回ERROR
     **/
    static STATUS create_sem(struct t_sem *p_sem)
    {
        if (p_sem == NULL) {
            PRINT_ERR("struct t_sem is empty");
            return ERROR;
        }
    
        if (p_sem->sem != NULL) {
            PRINT_ERR("the semphore is exist");
            return OK;
        }
    
        if (p_sem->type == SEM_BIN)
            p_sem->sem = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);
        else
            p_sem->sem = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE);
    
        if (p_sem->sem == SEM_ID_NULL) {
            printf("semphore (%s) create failed...\n", p_sem->name);
            return ERROR;
        }
        return OK;
    }
    
    /**
     * @查找指定信号量
     * @p_sem:信号量类集合        name: 信号量名
     * @成功返回信号量偏移量, 失败返回ERROR
     **/
    static s32_t find_sem(struct sem *p_sem, s8_t *name)
    {
        s32_t i;
    
        if ((p_sem->num == 0) || (name == NULL))
            return ERROR;
    
        for (i=0; i<p_sem->num; i++) {
            if (strcmp(p_sem->info[i].name, name) == 0)
                break;
        }
    
        return ((i == p_sem->num) ? ERROR : i);
    }
    
    /**
     * @信号量注册
     * @p_sem:信号量类集合        p_info:加入信号量信息
     **/
    void resgister_sem(struct sem *p_sem, struct t_sem *p_info)
    {
        if (p_info == NULL) {
            PRINT_ERR("the register sem cmd class parameter error");
            return;
        }
    
        if (p_sem->num >= MAX_SEM_NUM) {
            PRINT_ERR("the sem cmd class is full");
            return;
        }
    
        if (find_sem(p_sem, p_info->name) != ERROR)
            return;
    
        memcpy(&p_sem->info[p_sem->num], p_info, sizeof(struct t_sem));
        create_sem(&p_sem->info[p_sem->num]);
        p_info->sem = p_sem->info[p_sem->num].sem;
        p_sem->num++;
    }
    
    
    /**
     * @通过信号量名获取信号量
     * @p_sem:信号量类集合        name: 信号量名
     **/
    void get_sem_by_name(struct sem *p_sem, char *name)
    {
        s32_t idx = find_sem(p_sem, name);
    
        if (idx == ERROR) {
            printf("semphore (%s) not found...\n", name);
            return;
        }
        semTake(p_sem->info[idx].sem, WAIT_FOREVER);   /* 等待获取信号量 */
    }
    
    /**
     * @通过信号量名释放信号量
     * @p_sem:信号量类集合        name: 信号量名
     **/
    void lose_sem_by_name(struct sem *p_sem, char *name)
    {
        s32_t idx = find_sem(p_sem, name);
    
        if (idx == ERROR) {
            printf("semphore (%s) not found...\n", name);
            return;
        }
        semGive(p_sem->info[idx].sem);      /* 释放信号量*/
    }
    
    /**
     * @获取信号量
     * @p_sem:信号量类
     **/
    void get_sem(struct t_sem *p_sem)
    {
        if ((p_sem == NULL) || (p_sem->sem == SEM_ID_NULL))
            return;
    
        semTake(p_sem->sem, WAIT_FOREVER);   /* 等待获取信号量 */
    }
    
    /**
     * @释放信号量
     * @p_sem:信号量类
     **/
    void lose_sem(struct t_sem *p_sem)
    {
        if ((p_sem == NULL) || (p_sem->sem == SEM_ID_NULL))
            return;
    
        semGive(p_sem->sem);   /* 释放信号量*/
    }
    
    /**
     * @同步信号量释放
     * @p_sem:信号量类集合    time:定时器时间
     **/
    void lose_sync_sem(struct sem *p_sem, u64_t time)
    { 
        s32_t i;
        for (i=0; i<p_sem->num; i++) {
            if ((p_sem->info[i].type == SEM_MUTEX) || (p_sem->info[i].period == 0))
                continue;
    
            if (time == p_sem->info[i].period)
                semGive(p_sem->info[i].sem);    /* 释放信号量*/      
        }
    }
    
    /**
     * @设置指定信号量周期
     * @p_sem:信号量类集合        name:信号量名       period:周期
     **/
    void set_sem_period(struct sem *p_sem, s8_t *name, s32_t period)
    {
        s32_t idx = find_sem(p_sem, name);
    
        if ((idx == ERROR) || (p_sem->info[idx].type == SEM_MUTEX))
            return;
    
        p_sem->info[idx].period = period;
    }
    
    /**
     * @创建信号量类
     * @p_sem:信号量类        src:源信号量类       dst:目的信号量类
     **/
    void new_sem(struct sem *p_sem, struct t_sem *src, struct t_sem *dst)
    {
        memcpy(dst, src, sizeof(struct t_sem));
        resgister_sem(p_sem, dst);
    }
    
    /**
     * @显示指定信号量信息
     * @p_sem:信号量类        name:信号量名       level:0-显示摘要,1-显示详情    
    **/
    void show_sem_info(struct sem *p_sem, char *name, int level)
    {  
        s32_t idx = find_sem(p_sem, name);
    
        if (idx == ERROR) {
            printf("semphore (%s) not found...\n", name);
            return;
        }
    
        semShowInit();
        semShow(p_sem->info[idx].sem, level);
    }
    

     main.c

    /**
     * @Filename : main.c
     * @Revision : $Revision: 1.00 $
     * @Author : Feng(更多编程相关的知识和源码见微信公众号:不只会拍照的程序猿,欢迎订阅)
     * @Description : 信号量类使用示例
    **/
    
    #include <vxWorks.h>     
    #include <math.h>    
    #include "stdioLib.h"     
    #include "strLib.h"     
    #include "task.h"
    #include "sem.h"
    #include "feng_type.h"
    
    struct sem     sem;    /* 保存系统信号量信息 */
    struct t_task s_task, s_task1;
    struct t_sem s_sem, s_sem1;
    
    /**
     * @定时输出打印信息
    **/
    static void _thread(void)
    {  
        static int cnt = 0;
    
        while (1) { 
            get_sem(&s_sem);
            printf("cnt is %d...\n", cnt++);
        }
    }
    
    /**
     * @定时输出打印信息
     * get_sem_by_name(&sem, "my_sem1");
    **/
    static void _thread1(void)
    {  
        static int cnt1 = 0;
    
        while (1) { 
            get_sem(&s_sem1);
    
            printf("cnt1 is %d...\n", cnt1++);
        }
    }
    
    /**
     * @显示指定信号量信息
     * @name:信号量名        level:0-显示摘要,1-显示详情    
    **/
    void show(char *name, int level)
    {
        show_sem_info(&sem, name, level);
    }
    
    /**
     * @创建任务
     * @p_task:任务类    name:任务名        thread:函数
    **/
    void _create_task(struct t_task *p_task, char *name, FUNCPTR thread)
    {
        strcpy(p_task->name, name);     
        p_task->options    = VX_FP_TASK;
        p_task->stackSize  = 50 * 1024;
        p_task->pFunc      = thread;
        p_task->tid        = NULL;
        p_task->core       = 0;
        p_task->priority   = 102;
    
        create_task(p_task);
        start_task(p_task);
    }
    
    /**
     * @创建任务
     * @p_task:任务类    name:任务名        thread:函数
    **/
    void _create_sem(struct t_sem *p_sem, char *name, E_SEM_TYPE type)
    {
        strcpy(p_sem->name, name);      
        p_sem->period = 100;
        p_sem->type = type;
        p_sem->sem = SEM_ID_NULL;
    
        resgister_sem(&sem, p_sem);
    }
    
    int main(void)
    {
        static int time_cnt = 0;
    
        sysClkRateSet(100);         /* 时间片设置 */
    
        _create_sem(&s_sem, "my_sem", SEM_BIN);
        _create_sem(&s_sem1, "my_sem1", SEM_BIN);
    
        _create_task(&s_task, "my_task", (FUNCPTR)_thread);
        _create_task(&s_task1, "my_task1", (FUNCPTR)_thread1);
    
        while (1) { 
            taskDelay(1000);        /* 10s */
            time_cnt++;
    
            if (time_cnt & 0x01)
                lose_sem_by_name(&sem, "my_sem");
    
            if (time_cnt == 6) {
                time_cnt = 0;
                lose_sem_by_name(&sem, "my_sem1");
            }
    
        }
    
        return 0;
    }
    

    验证

    创建应用工程sem_test,输入相关测试代码,运行后如下图所示。

    注意:若不知道工程如何创建以及运行,可参见小编文章《实时系统vxWorks - 任务(重要)》和《实时系统vxWorks - 加载应用程序的方法》。

    输入命令show “my_sem”, 1,查看信号量“my_sem”详情。

    输入命令show “my_sem1”, 1,查看信号量“my_sem1”详情。

    往期 · 推荐

    实时系统vxWorks - 任务(重要)

    实时系统vxWorks - 加载应用程序的方法

    实时系统vxWorks - 在线调试

    实时系统vxWorks - 虚拟机环境搭建

    实时系统vxWorks - zynq7020移植vxWorks

    关注

    更多精彩内容,请关注微信公众号:不只会拍照的程序猿,本人致力分享linux、设计模式、C语言、嵌入式、编程相关知识,也会抽空分享些摄影相关内容,同样也分享大量摄影、编程相关视频和源码,另外你若想要获得更多内容教程请关注公众号:不只会拍照的程序猿。

    展开全文
  • Vxworks信号量详解

    千次阅读 2013-09-02 10:50:19
    任务异常处理 程序或数据错误可能导致硬件异常;如非法指令,总线或地址错误,除0除外,Vxworks异常处理负责这些异常处理。 一般默认处理是将引进异常的任务挂起,保存该任务引起异常时运行状态...Vxworks只要使用


    任务异常处理

    程序或数据错误可能导致硬件异常;如非法指令,总线或地址错误,除0除外,Vxworks异常处理负责这些异常处理。

    一般默认处理是将引进异常的任务挂起,保存该任务引起异常时运行状态。 内核和其他任务继续运行。

     代码的共享与重入:

      Vxworks中, 一段子程序可能被多个任务调用,共享代码就是被多个任务执行的代码。共享代码是系统更加有效和易于管理。

    Vxworks只要使用一些重入技术:

    1. 动态可变堆栈;

    2. 信号量对全局变量和静态变量进行保护

    3.任务可变

    动态可变堆栈:

      许多子程序是纯粹的代码,除了动态可变堆栈外没有他们自己的数据,这些程序是可重入的,因为每个在调用该子程序的任务都有它自己的堆栈区。

    全局和静态变量的保护:

     任务可变(task  variables)

      一些被多个任务调用的程序,每个任务可能要求各自独立使用它的全局或静态变量。

    Vxworks 提供了taskvariable()可变任务的方法。

    Vxworks提供了几个系统任务

     根任务(root task): tUsrRoot

       根任务tUsrRoot 是被内核第一个执行的任务,根任务的进入点式usrRoot,(在config/all/usrConfig.h)并初始化几乎所用的xvworks工具。初始化完成后,根任务将自己删除,

    The logging Task :tlogTask

    Log任务:tLogtask被vxworks模块用于登陆系统信息。

    异常处理任务:tExcTask

       异常处理任务,tExcTask 支持vxworks异常处理,你必须在系统中有最高优先级。不要将该任务挂起,删除或改变优先级。

    网络任务:tNetTask

    任务间通信:

      Vxworks提供了丰富的机制来 进行任务间通信:

      共享内存;信号量,消息队也和管道,socket(套接字);信号(signals)处理异常

    共享数据结构(共享内存)

       互斥

       当一块共享地址空间用来交换数据时,避免冲突很关键,一般用关中断,禁止抢占,信号量锁定资源。

    关中断 

       关闭中断后,其它程序就不能抢占cpu;

     函数: intLock() intUnlock()

      注意: 实时系统要求对外界的事件能做出实时响应,如果关闭中断后,就无法保证,建议一般尽量少用,或者关中断时间尽量的短。

    禁止优先级抢占

      使用这种方法的高优先级任务不能打断在执行的任务,但可以中断,

    函数 :taskLock() taskUnLock( )

    这种方法还有缺点,就是即使高优先级任务和共享资源毫无关系式也无法进行抢占执行,这样就和实时性有点冲突, 所以我们要求锁定优先级的时间尽量的短,结果更好的办法是用信号量。

    信号量:

     Vxworks中信号量是高优化的,提供了最快的任务间通信机制。信号量解决了互斥和同步问题。

    互斥:信号量可以保护共享资源,没有锁定中断和优先级带来的不良后果。

    同步:信号量通过外部事件来调整任务的执行。

    Wind 提供了三种不同的信号量来解决不通类型的问题

     Binary(两进制):最快,最通用的信号量,在解决同步和互斥问题上最优;

     Mutual-exclusion(互斥信号量):特殊的binary信号量,在解决互斥上最优;优先级传递,安全删除,递归。

    Counting:适用于共享资源不止一个情况;

    信号量控制:

      Vxworks为不同的信号量设计了相同的控制接口。只创建函数不同,

    创建信号量的时候,队列类型要指定,等待信号量的任务依据信号量的类型被放不同的等待队列。

    注意:删除信号量要小心,特别是互斥信号量,要避免删除一个信号量的时候有其他任务需要改信号量。

    Binary信号量(二进制信号量)

     信号量有两种功能:同步和互斥,

     一个binary信号来那个有两种状态:可利用(full)和不可利用(empty)

    用semTake()来获得信号量;如果使用该函数的时候,信号量处于full状态,则调用函数后信号量变为empty,否则根据该信号量的类型把申请信号量的任务挂起到相应的等待队列中。当然如果任务是不等待队列信号,则任务继续执行。

      释放信号来那个semGive()

    semBCreate()   创建一个二进制信号量

    semMcreate()   创建一个互斥信号量

    semCCreate()   创建一个计数器信量

    semDelete()    终止信号量

    semTake()     获得信号量

    semGive()     给出信号量

    semFlush()    解锁所有正在等待某信号量的任务

    函数原型:

     SEM_ID semBCreate
        (
        int         options,      /* semaphore options */
        SEM_B_STATE initialState  /* initial semaphore state */
        )
     SEM_ID semMCreate
        (
        int options               /* mutex semaphore options */
        )
    SEM_ID semCCreate
        (
        int options,              /* semaphore option modes */
        int initialCount          /* initial count */
        )
    STATUS semDelete
        (
        SEM_ID semId              /* semaphore ID to delete */
        )
    STATUS semTake
        (
        SEM_ID semId,             /* semaphore ID to take */
        int    timeout            /* timeout in ticks */
        )
    STATUS semGive
        (
        SEM_ID semId              /* semaphore ID to give */
        )
    STATUS semFlush
        (
        SEM_ID semId              /* semaphore ID to unblock everyone for */
        )

    互斥功能:

       初始化为full, 可以保护共享资源。

    #include<vxworks.h>

    #include<semLib.h>

    SEM_ID  semMutex;

    semMutex = semBCreate(SEM_Q_PRIORITY,SEM_FULL);

    //用semTake()和semGive()来获得或释放信号量

    semTake(semMutex,WAIT_FOREVER);

    critical region .only accessible by a single task at a time;

    semGive(semMutex);

    同步功能:

      使用同步功能的时候,要把信号量初始化为empty ,当任务后中断发生某事件发生后将调用semGive() 函数将其变为full。

     Example:

    #include<vxWorks.h>

    #include<semLib.h>

    #include<arch/arch/ivarch.h>

    SEN_ID syncSem ;

    Init(int someIntNum)

    {

     intConnect(INUM_TO_IVEC(someIntNum),eventInterruptSvcRout,0);

     syncSem = semBCrea(SEM_Q_FILE,SEM_EMPTY);

    taskSpawn(“sample”,100,0,2000,task1,0,0,0,0,0,0,0,0,0);

    }

    Task1(void)

    {

     SemTake(syncSem,WAIT_FOREVER);

     Printf(“task 1 got semaphore /n”);

     

    }

    eventInterruptSvcRout(void)

    {

     semGive(syncSem);

    }




    展开全文
  • VxWorks -- 信号量

    2020-12-17 14:31:17
    VxWorks学习笔记 -- 信号量 一.信号量的概念 是实现任务互斥、同步操作的主要机制。VxWorks提供的信号量经过了高度优化,在所有任务间通信机制中,速度最快。   二.信号量的分类 Binary Semaphores(二...

    VxWorks学习笔记 -- 信号量

    一.信号量的概念

    是实现任务互斥、同步操作的主要机制。VxWorks提供的信号量经过了高度优化,在所有任务间通信机制中,速度最快。

     

    二.信号量的分类

    Binary Semaphores(二进制):完成互斥、同步操作的最佳方式;速度最快,最常用。

    Mutual Exclusion Semaphores(互斥):一种特殊的二进制信号量,专门针对互斥操作进行了优化。

    Counting Semaphores(计数):类似于二进制信号量,可记录信号量释放的次数,可监视同一资源上的多个实例。

     

     

    三.Binary Semaphores(二进制信号量)

        Task经常会等待事件或需获取资源。查询(polling)在RealTime系统中原则上不允许,最好采用Pending,等待事件或资源。

    状态图:

     

    说明:

    1.为某个资源调用semBCreate()创建一个binary semaphore 并规定:

    SEM_Full (资源可用) SEM_Empty (资源不可用).

    2.资源不可用时Task调用semTake()进入Pending直到semaphore被Given

     

    相关函数:

    SEM_ID semBCreate ( int options, /* semaphore options */

    SEM_B_STATE initialState  /* initial semaphore state */
    

    )

    STATUS semTake
    (
    SEM_ID semId, /* 需要获取的信号量ID */

    int timeout /* 超时时间(tick)/no-wait/forever */
    

    )

     

    ISR(中断服务程序)不能调用semTake()操作!

     

     

    STATUS semGive ( SEM_ID semId /* 需要释放的信号量ID */ )

     

     

    semFlush()

     

    应用方向:

    1.互斥操作:是指不同任务可以利用信号量互斥地访问临界资源。这种互斥的访问方式比中断禁止(interrupt disable) 与优先级锁定

    (preemptive locks)两种互斥方式具有更加精确的粒度。

    互斥操作时初始状态设为(SEM_FULL)可用。并在同一个Task中成对、顺序调用semTake()、semGive()。

     

    2.同步操作:是指一个任务可以利用信号量控制自己的执行进度,使自己同步于一组外部事件。同步操作时初始状态设为(SEM_EMPTY)不可用。在不同Task中分别单独调用semTake()、semGive()。

     

     

    四.Mutual Exclusion Semaphores(互斥信号量)

        互斥信号量是一种特殊的二进制信号量,它是针对使用二进制信号量进行互斥操作时存在的一些问题设计的。互斥信号量主要增加了对优先级倒置、删除安全以及递归访问的处理。

    状态图:

    相关函数:

    SEM_ID semMCreate ( int options /* mutex semaphore options */ )

    区别:

    1.互斥信号量只能用于互斥操作。

    2.只能由已经获取了互斥信号量的任务去释放它。

    3.中断服务程序(ISR)不可以释放(semGive())互斥信号量。

    4.互斥信号量不支持semFlush()操作。

     

    应用方向:

    1.避免优先级倒置(Priority Inversion)

    在上图中,task2等待task1的资源,于是处于Pend状态,这时一个中等优先级的task进来,并抢占了task1CPU,此时的表现是低优先级task在高优先级的task2前执行。这种现象就是先级倒置。

     

    使用semId = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE);就可以避免倒置。

    此时,task1的优先级提升与task2一样,至到task2执行完成。

    SEM_INVERSION_SAFE不能与SEM_Q_FIFO配对!

     

    2.Deletion Safety(安全删除)

    使用:semId = semMCreate(SEM_Q_FIFO | SEM_DELETE_SAFE);可以实现安全删除。

    其实质是:在Task对互斥信号量执行semTake()操作并成功占有该信号量之前,隐含执行了taskSafe()操作;在执行semGive()操作之后,隐含执行taskUnsafe()操作。

    如果一个任务task1试图删除一个已经被保护起来的任务task2,task1则将被阻塞起来,直到task2解除保护(释放掉具有删除保护的互斥信号量)才能完成删除工作。

     

    3.递归访问

    InitFun() { sem_ID = semMCreate(…); }

    funB()
    {
    semTake(sem_ID, SEM_FOREVER);

    /*访问临界资源*/
    
    semGive(sem_ID);
    

    }

    funA()
    {
    semTake(sem_ID, SEM_FOREVER);

    /*访问临界资源*/
    
    funB();  //递归访问, 而不会死锁
    
    semGive(sem_ID);
    

    }

     

    五.Counting Semaphores(计数信号量)

    计数信号量与二进制信号量都可以用于任务之间的同步与互斥。其不同点在于,计数信号量可记录信号量释放的次数,可以用来监视某一资源的使用状况。

    状态图:

    相关函数:

    SEM_ID semCCreate ( int options, /* semaphore option modes */

    int initialCount          /* initial count */
    

    )

     

    展开全文
  • VxWorks信号量小结

    千次阅读 2018-04-04 17:22:44
    信号量VxWorks中任务间通信的一种基本手段...首先,信号量使用必须包括semLib.h这个头文件。下面分类进行简单说明:1.二进制信号量 创建二进制信号量的函数:SEM_ID semBCreate( int options , SEM_B_STATE i...
         信号量是VxWorks中任务间通信的一种基本手段。VxWorks提供了三种信号量:二进制信号量、互斥信号量和计数信号量。下面针对实验中的程序编写和调试,讲一讲我对信号量的理解。
    
    首先,信号量的使用必须包括semLib.h这个头文件。下面分类进行简单说明:
    1.二进制信号量
       创建二进制信号量的函数:
    SEM_ID semBCreate( int options , SEM_B_STATE initalState)
       该函数执行后,返回一个二进制信号量的ID。
       函数参数说明:
       options可以为SEM_Q_PRIORITY(值为0x1)和SEM_Q_FIFO(值为0x0)。这个选项是设定使用信号量的任务对信号量的抢占方式,当信号量可用时若有多个任务在等待,前者设定优先级高的任务先抢占,后者则设定处在等待队列前面的任务先抢占。
        initalState可以为SEM_FULL(值为1)和SEM_EMPTY(值为0)。前者初始化信号量为满(可用),后者初始化信号量为空(不可用)。
    我对二进制信号量的使用的一些理解:
    a.二进制信号信号量一般用在对那些独占性资源的分配中,take和give在同一个任务当中。比如有两个任务都需要用到打印机资源,则需要看信号量的option情况,如下定义A、B两个任务,都需要使用同一个打印机:  
    TaskA  
    {
            Take 信号量 
            打印
            Give信号量
        }  
    TaskB  
    {  
            Take信号量 
            打印  
            Give信号量
    }  


    b.二进制信号量用在同步的时候,一般take和give在不同的任务当中。如下面的A、B两个任务,对打印这个动作进行同步,防止没有纸而打印的情况:
    TaskA  
    {
            准备打印纸 
            Give信号量
        }  
    TaskB  
    {   
            Take信号量 
            开始打印  
    }
    2.互斥信号量
    互斥信号量的创建函数:
    SEM_ID semMCreate(int optipns)
    该函数执行后,返回一个互斥信号量的ID。
    options参数说明:
    SEM_Q_PRIORITY(值为0x1):需要获取该信号量的任务基于优先级顺序排列。
    SEM_Q_FIFO(值为0x0):需要获取该信号量的任务基于等待任务队列的先进先出顺序排列。
    SEM_DELETE_SAFE(值为0x4):保护任务防止意外删除,当执行semTake操作时默认为taskSafe,当执行semGive的时候默认为taskUnsafe。
    SEM_INVERSION_SAFE(值为0x8):保护系统,防止出现优先级倒置现象。
    SEM_EVENTSEND_ERR_NOTIFY(值为0x10):任务发送事件失败时,会发送错误信号。
    一般来说,互斥信号量主要用于保护临界资源, take和give成对出现。比如下面的A、B两个任务都要对数据库中的同一项进行操作,用来避免数据库在被操作时被其它任务所改写:  
    TaskA  
    {         
           Take信号量  
           写数据库  
           Give信号量
    }  
    TaskB  

           Take信号量  
           写数据库   
           Give信号量  
     }
       可以看出,互斥信号量和二进制信号量都能实现任务互斥访问临界资源的问题,但是这两者还是有一些不同的。下面谈谈互斥信号量与二进制信号量相比的优点:互斥信号量可以解决在互斥操作用二进制信号量时所引起的问题。这些问题包括资源拥有者的删除保护,以及由资源竞争引起的优先级逆转。先说资源的删除保护。互斥引起的一个问题会涉及到任务删除,即在由信号量保护的临界区中,需要防止执行任务被意外地删除。删除一个在临界区执行的任务是灾难性的,资源会被破坏,保护资源的信号量会变为不可获得,从而该资源不可被访问。通常删除保护是与互斥操作共同提供的。由于这个原因,互斥信号量通常提供选项来隐含地提供前面提到的任务删除保护的机制(即SEM_DELETE_SAFE这个参数选项)。
       再说说优先级逆转。优先级逆转发生在一个高优先级的任务被强制等待一段不确定的时间以便一个较低优先级的任务完成执行。考虑下面的假设:T1,T2和T3分别是高、中、低优先级的任务。T3通过拥有信号量而获得相关的资源。当T1抢占T3,为竞争使用该资源而请求相同的信号量的时候,它被阻塞。如果我们假设T1仅被阻塞到T3使用完该资源为止,情况并不是很糟。毕竟资源是不可被抢占的。然而,低优先级的任务并不能避免被中优先级的任务抢占,一个抢占的任务如T2将阻止T3完成对资源的操作。这种情况可能会持续阻塞T1等待一段不可确定的时间。这种情况就叫做优先级逆转,因为尽管系统是基于优先级的调度,但却使一个高优先级的任务等待一个低优先级的任务完成执行。
       最后谈谈优先级继承。互斥信号量有一个选项允许实现优先级继承的算法(即SEM_INVERSION_SAFE这个参数选项)。优先级继承通过在T1被阻塞期间提升T3的优先级到T1解决了优先级逆转引起的问题。这防止了T3,间接地防止T1,被T2抢占。通俗地说,优先级继承协议使一个拥有资源的任务以等待该资源的任务中优先级最高的任务的优先级执行。当执行完成,任务释放该资源并返回到它正常的或标准的优先级。因此,继承优先级的任务避免了被任何中间优先级的任务抢占。
    3.计数信号量
    计数信号量的创建函数:
    SEM_ID semCCreate(int options, int initialCount)
    该函数执行后,返回一个计数信号量的ID。
    options参数说明:
    SEM_Q_PRIORITY(值为0x1):需要获取该信号量的任务基于优先级顺序排列。
    SEM_Q_FIFO(值为0x0):需要获取该信号量的任务基于等待任务队列的先进先出顺序排列。
    SEM_EVENTSEND_ERR_NOTIFY(值为0x10):该参数可激活由于semGive失败而返回ERROR值。
    initialCount参数为初始化计数信号量的值。由此可见,计数信号量的值是上不封顶的,只要能不断的semGive,信号量就可以增加。因此在使用计数信号量的时候必须注意信号量的值的边界问题,就是要根据实际资源的大小来确定。
        计数信号量是任务同步和互斥的另一种实现方式,其用法和二进制信号量类似,只是它可以保持信号量被释放的次数,主要用于保护一个资源的多个例程。
     
    总结:信号量的使用是操作系统中一个非常重要的工具,几乎所有的操作系统都支持信号量的操作。信号量在资源的分配以及防止死锁方面具有不可替代的作用。
    展开全文
  • vxworks 信号量的用法

    2012-02-14 11:44:08
    二进制信号信号量用于同步,一般take和give在不同的任务当中. 比如: TaskA {  准备打印纸  Give信号量 } TaskB {  Take信号量  开始打印 } 互斥信号量主要用于保护临界支援,成对出现. ...
  • 资源包含了vxworks多任务(task和semaphore信号量及事件)的相关编程例子,通过创建多任务的简单例子,帮助大家了解taskSpawn函数、信号量semaphore、以及事件event的使用方法。
  • Vxworks信号量分析

    2008-12-22 20:21:43
    Wind内核中有二进制信号量、计数信号量和互斥信号量三种类型,为了使应用程序具有可移植性,还提供了POSIX(可移植操作系统接口)信号量。在Vxorks操作系统中,信号量是实现任务同步的主要手段,也是解决任务同步...
  • VxWorks信号量问题

    2018-07-25 14:21:00
    VxWorks主要提供如下API进行信号量的创建、获取和释放: 参数1:SEM_Q_PRIORITY,SEM_Q_FIFO SEM_Q_PRIORITY(值为0x1):需要获取该信号量的任务基于优先级顺序排列。SEM_Q_FIFO(值为0x0):需要获取该信号量的...
  • vxworks 信号量

    2015-12-29 17:00:03
    VxWorks中,信号量是实现任务同步的主要手段,也是解决任务同步的最佳选择。 关于互斥的实现: 使用二进制信号量可以很方便的实现互斥,互斥是指多任务在访问临界资源时具有排他性。为了使多个任务互斥访问临界...
  • vxWorks互斥信号量示例

    千次阅读 2016-02-08 21:30:20
    #include "vxWorks.h" #include "semLib.h" #include "taskLib.h" #include "logLib.h" #include "sysLib.h" #include "stdio.h" #define CONSUMER_TASK_PRI 98 /* Priority of the consumerTask task
  • vxworks实验信号量

    2008-12-24 10:34:29
    vxworks实验,信号量。有实例代码。vxworks实验信号量。有实例代码。
  • Vxworks信号量高阶分析(互斥死锁)

    千次阅读 2013-09-03 10:45:25
    VXWORKS实时操作系统中信号量用于多任务同步与互斥的讨论 赵佑春 (南京理工大学自动化系,江苏 南京210094) 摘要:实时操作系统中对任务的响应时间提供了机制上的保障,但任务的同步与互斥又会削弱对任务响应的...
  • VxWorks学习笔记 -- 信号量

    万次阅读 多人点赞 2011-04-14 13:23:00
    VxWorks提供的信号量经过了高度优化,在所有任务间通信机制中,速度最快。   二.信号量的分类 Binary Semaphores(二进制):完成互斥、同步操作的最佳方式;速度最快,最常用。 Mutual Exclusion Semaphores...
  • VxWorks为保证各个独立的任务可以协同工作,提供了一整套任务的通信机制,包括信号量、共享内存、消息队列、管道、信号、事件等,此外还有一些网络编程机制如套接字。本文主要对信号量进行总结介绍。
  • VxWorks信号量是提供任务间通信、同步和互斥的最优选择,提供任务间最快速的通信。也是提供任务间同步和互斥的主要手段。VxWorks提供3种信号量来解决不同的问题。   二进制信号量:最快的最常用的信号量,可...
  • vxworks信号量分析

    2014-04-26 10:31:33
    VxWorks信号量是提供任务间通信、同步和互斥的最优选择,提供任务间最快速的通信。也是提供任务间同步和互斥的主要手段。VxWorks提供3种信号量来解决不同的问题。   二进制信号量:最快的最常用的信号量,可...
  • vxworks信号量机制实现同步任务
  • VxWorks中,信号量是实现任务同步的主要手段,也是解决任务同步的最佳选择。 关于互斥的实现: 使用二进制信号量可以很方便的实现互斥,互斥是指多任务在访问临界资源时具有排他性。为了使多个任务互斥访问临界...
  • VxWorks 信号量

    千次阅读 2010-12-23 15:40:00
    <br />      VxWorks提供了多种任务间通信方式,主要有:   (1)共享内存(Shared Memory),用于简单的数据共享;   由于...   信号量VxWorks所提供
  • // 信号量演示 #include<iostream> #include <windows.h> using namespace std; HANDLE g_ThreadSema; //创建内核对象,用来初始化信号量 DWORD WINAPI Func(LPVOID); DWORD WINAPI Func1(LPVOID p...
  • VXWORKS实时操作系统中信号量用于多任务同步与互斥的讨论.pdf
  • 最近在做vxworks下的项目开发 感觉其自带的消息队列MSG_Q_ID和信号量SEM_ID特别好用。于是想办法在vc做了个类似的东西,函数原型都一致。这样,我在vxworks下做好的程序几乎不用做太多修改,就可以移植到windows平台...
  • VxWorks信号量机制分析

    千次阅读 2009-03-21 22:53:00
    VxWorks的信号量机制分析 VxWorks信号量是提供任务间通信、同步和互斥的最优选择,提供任务间最快速的通信。也是提供任务间同步和互斥的主要手段。VxWorks提供3种信号量来解决不同的问题。 二进制信号量:最快的最...
  • #include "vxWorks.h" #include "taskLib.h" #include "semLib.h" #include "stdio.h" #include "sysLib.h" SEM_ID semId; LOCAL SEM_ID semId1; /* semaphore id of binary semaphore 1 */ LOCAL SE
  • vxworks系统学习----二进制信号量

    千次阅读 2016-07-29 14:52:33
    vxworks使用信号量工具对互斥与任务同步进行操作。在wind内核中存在二进制信号量、互斥信号量及计 数信号量。互斥:当共享地址空间进行简单的数据交换时,为避免竞争需要对内存进行互锁,即多个任务访问共享内存...
  • #include "vxWorks.h" #include "wdLib.h" #include "stdio.h" #include "semLib.h" #include "taskLib.h" #include "usrLib.h" #include "sysLib.h" /* defines */ #define TASK_WORK_TIME 2 /* 2 ticks */
  • VxWorks学习篇-二进制信号量

    万次阅读 2016-10-30 22:03:47
    目前国内雷达信号处理平台上所用的操作系统大多为VxWorks,在VxWorks中,信号量是一种在不同任务间有效传递消息的机制,其中包括二进制信号量、计数型信号量、互斥型信号量。在这些信号量中,二进制信号量使用最为...
  • VxWorks5.5中,为了保证各个独立的任务可以协同工作,提供了一整套任务间的通信机制,主要包括信号量,共享内存,消息队列,管道,信号,事件。 当然除了上面这些机制,VxWorks5.5还提供了一些网络通信(socket),...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,528
精华内容 1,411
关键字:

vxworks信号量使用