线程间同步(信号量、互斥量、事件集)笔记

        多个执行单元(线程、中断)同时执行临界区,操作临界资源,会导致竟态产生,为了解决这种竟态问题,RT-Thread 提供了如下三种同步互斥机制:信号量、互斥量(锁)、事件集

1、信号量

      信号量是一种轻型的用于解决线程间同步问题的内核对象,线程可以获取或释放它,从而达到同步或互斥的目的。

     每个信号量对象都有一个信号量值和一个线程等待队列,信号量的值对应了信号量对象的实例数目、资源数目,假如信号量值为 5,则表示共有 5 个信号量实例(资源)可以被使用,当信号量实例数目为零时,再申请该信号量的线程就会被挂起在该信号量的等待队列上,等待可用的信号量实例(资源)。

例:

      思路如图所示,初始化sem1的信号量值为1,sem2的信号量值为0。程序运行时,先执行线程1(因为此时线程2下的sem2=0)获取sem1信号量(sem1=0),然后释放信号量sem2(此时sem2=1)进入线程2,在释放sem1进入线程1,照此循环往复。

线程间同步(信号量、互斥量、事件集)笔记_第1张图片

 1.1信号量结构体

struct rt_semaphore
{
    struct rt_ipc_object parent;  /**< inherit from ipc_object  继承自ipc_object类*/

    rt_uint16_t          value;       /**< value of semaphore. */
    rt_uint16_t          reserved;    /**< reserved field 预留*/ 
};
typedef struct rt_semaphore *rt_sem_t;

 1.2 信号量的使用和管理

       对一个信号量的操作包含:创建 / 初始化信号量、获取信号量、释放信号量、删除 / 脱离信号量。

创建和删除信号量(动态):

线程间同步(信号量、互斥量、事件集)笔记_第2张图片

       系统不再使用信号量时,可通过删除信号量以释放系统资源,适用于动态创建的信号量。调用这个函数时,系统将删除这个信号量。如果删除该信号量时,有线程正在等待该信号量,那么删除操作会先唤醒等待在该信号量上的线程(等待线程的返回值是-RT_ERROR),然后再释放信号量的内存资源。

/**
 * This function will delete a semaphore object and release the memory
 *
 * @param sem the semaphore object
 *
 * @return the error code
 *
 * @see rt_sem_detach
 */
rt_err_t rt_sem_delete(rt_sem_t sem)

初始化和脱离信号量(静态)

/**
 * This function will initialize a semaphore and put it under control of
 * resource management.
 *
 * @param sem the semaphore object
 * @param name the name of semaphore
 * @param value the initial value of semaphore
 * @param flag the flag of semaphore
 *
 * @return the operation status, RT_EOK on successful
 */
rt_err_t rt_sem_init(rt_sem_t    sem,
                     const char *name,
                     rt_uint32_t value,
                     rt_uint8_t  flag)

      脱离信号量就是让信号量对象从内核对象管理器中脱离,适用于静态初始化的信号量。使用该函数后,内核先唤醒所有挂在该信号量等待队列上的线程,然后将该信号量从内核对象管理器中脱离。原来挂起在信号量上的等待线程将获得 - RT_ERROR 的返回值。

/**
 * This function will detach a semaphore from resource management
 *
 * @param sem the semaphore object
 *
 * @return the operation status, RT_EOK on successful
 *
 * @see rt_sem_delete
 */
rt_err_t rt_sem_detach(rt_sem_t sem)

获取信号量

        线程通过获取信号量来获得信号量资源实例,当信号量值大于零时,线程将获得信号量,并且相应的信号量值会减 1,如果信号量的值等于零,那么说明当前信号量资源实例不可用,申请该信号量的线程将根据time参数的情况选择直接返回、或挂起等待一段时间、或永久等待,直到其他线程或中断释放该信号量。如果在参数time指定的时间内依然得不到信号量,线程将超时返回,返回值是 - RT_ETIMEOUT。

线程间同步(信号量、互斥量、事件集)笔记_第3张图片

  释放信号量

      释放信号量可以唤醒挂起在该信号量上的线程。2

/**
 * This function will release a semaphore, if there are threads suspended on
 * semaphore, it will be waked up.
 *
 * @param sem the semaphore object
 *
 * @return the error code
 */
rt_err_t rt_sem_release(rt_sem_t sem)

2 互斥量(锁)

       互斥量体现的是排他性,也是解决多线程同时操作临界区临界资源导致的竟态的一种方法。(类似于特殊的信号量——二值信号量)

区别:信号量可由不同线程释放互斥量只能由同一线程进行释放。

例子:

       如下图程序,进入线程1,然后上锁,虽然线程1在运行过程中启动了延时函数,线程1进入挂起状态,但是线程1上了锁,所以也不能运行其他线程,只有等线程1解锁后才能运行其他线程。

线程间同步(信号量、互斥量、事件集)笔记_第4张图片

2.1 互斥量的使用和管理

          互斥量的操作包含:创建 / 初始化互斥量、获取互斥量、释放互斥量、删除 / 脱离互斥量。

        创建和删除

线程间同步(信号量、互斥量、事件集)笔记_第5张图片

       不再使用互斥量时,通过删除互斥量以释放系统资源,适用于动态创建的互斥量。

当删除一个互斥量时,所有等待此互斥量的线程都将被唤醒,等待线程获得的返回值是

- RT_ERROR

/**
 * This function will delete a mutex object and release the memory
 *
 * @param mutex the mutex object
 *
 * @return the error code
 *
 * @see rt_mutex_detach
 */
rt_err_t rt_mutex_delete(rt_mutex_t mutex)

初始化和脱离互斥量

/**
 * This function will initialize a mutex and put it under control of resource
 * management.
 *
 * @param mutex the mutex object
 * @param name the name of mutex
 * @param flag the flag of mutex
 *
 * @return the operation status, RT_EOK on successful
 */
rt_err_t rt_mutex_init(rt_mutex_t mutex, const char *name, rt_uint8_t flag)

      使用该函数接口后,内核先唤醒所有挂在该互斥量上的线程(线程的返回值是-RT_ERROR) ,然后系统将该互斥量从内核对象管理器中脱离。

/**
 * This function will detach a mutex from resource management
 *
 * @param mutex the mutex object
 *
 * @return the operation status, RT_EOK on successful
 *
 * @see rt_mutex_delete
 */
rt_err_t rt_mutex_detach(rt_mutex_t mutex)

获取互斥量

/**
 * This function will take a mutex, if the mutex is unavailable, the
 * thread shall wait for a specified time.
 *
 * @param mutex the mutex object
 * @param time the waiting time
 *
 * @return the error code
 */
rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time)

释放互斥量

/**
 * This function will release a mutex, if there are threads suspended on mutex,
 * it will be waked up.
 *
 * @param mutex the mutex object
 *
 * @return the error code
 */
rt_err_t rt_mutex_release(rt_mutex_t mutex)

3 事件集

        事件集也是线程间同步的机制之一,一个事件集可以包含多个事件,利用事件集可以完成一对多,多对多的线程间同步。

一个线程和多个事件的关系可设置为:

       其中任意一个事件唤醒 线程,或几个事件都到达后唤醒线程,多个事件集合可以用一个32bit无符号整型变量来表示,变量的每一位代表一个事件,线程通过"逻辑与"或"逻辑或"将一个或多个事件关联起来,形成事件组合。

RT-Thread 定义的事件集有以下特点:

       事件只与线程相关,事件间相互独立

      事件仅用于同步,不提供数据传输功能

      事件无排队性,即多次向线程发送同一事件(如果线程还未来得及读走),其效果等同于只发送一次

例子:

线程间同步(信号量、互斥量、事件集)笔记_第6张图片

 

创建和删除

/*
 * event structure
 */
struct rt_event
{
    struct rt_ipc_object parent;      /**< inherit from ipc_object */

    rt_uint32_t          set;         /**< event set */
};
typedef struct rt_event *rt_event_t;

/**
 * This function will create an event object from system resource
 *
 * @param name the name of event
 * @param flag the flag of event RT_IPC_FLAG_FIFO RT_IPC_FLAG_PRIO
 *
 * @return the created event, RT_NULL on error happen
 */
rt_event_t rt_event_create(const char *name, rt_uint8_t flag)


/**
 * This function will delete an event object and release the memory
 *
 * @param event the event object
 *
 * @return the error code
 */
rt_err_t rt_event_delete(rt_event_t event)

 初始化和脱离 

/**
 * This function will initialize an event and put it under control of resource
 * management.
 *
 * @param event the event object
 * @param name the name of event
 * @param flag the flag of event
 *
 * @return the operation status, RT_EOK on successful
 */
rt_err_t rt_event_init(rt_event_t event, const char *name, rt_uint8_t flag)


/**
 * This function will detach an event object from resource management
 *
 * @param event the event object
 *
 * @return the operation status, RT_EOK on successful
 */
rt_err_t rt_event_detach(rt_event_t event)

发送事件

/**
 * This function will send an event to the event object, if there are threads
 * suspended on event object, it will be waked up.
 *
 * @param event the event object
 * @param set the event set
 *
 * @return the error code
 */
rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set)

接收事件

/**
 * This function will receive an event from event object, if the event is
 * unavailable, the thread shall wait for a specified time.
 *
 * @param event the fast event object
 * @param set the interested event set
 * @param option the receive option, either RT_EVENT_FLAG_AND or
 *        RT_EVENT_FLAG_OR should be set. RT_EVENT_FLAG_CLEAR 
 * @param timeout the waiting time  RT_WAITING_FOREVER RT_WAITING_NO
 * @param recved the received event, if you don't care, RT_NULL can be set.
 *
 * @return the error code
 */
rt_err_t rt_event_recv(rt_event_t   event,
                       rt_uint32_t  set,
                       rt_uint8_t   option,
                       rt_int32_t   timeout,
                       rt_uint32_t *recved)

你可能感兴趣的:(RT_Thread应用入门,单片机,嵌入式硬件,c语言,linux)