线程间同步[信号量]

一.信号量

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

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

二.信号量的使用和管理

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

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

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

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

#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>


rt_sem_t sem1;

int main(void)
{
    sem1=rt_sem_create("sem1", 1, RT_IPC_FLAG_FIFO);
    if(sem1==RT_NULL)
    {
        LOG_E("rt_sem_create failed...\n");
        return -RT_ENOMEM;
    }
        LOG_E("rt_sem_create successed...\n");
}

四. 初始化和脱离信号量

/**
 * 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)
/**
 * 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
 */
#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>



struct rt_semaphore sem2;

int main(void)
{


    rt_sem_init(&sem2, "sem2", 0, RT_IPC_FLAG_FIFO);
    if(sem1==RT_NULL)
     {
          LOG_E("rt_sem_init failed...\n");
        return -RT_ENOMEM;
     }
        LOG_E("rt_sem_init successed...\n");
}

五.获取信号量

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

六.释放信号量

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

/**
 * 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)

七.信号量实例

#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>


 rt_sem_t sem1;
 struct rt_semaphore sem2;

 rt_thread_t th1,th2;
 int flags=0;

 //线程1的入口函数
 void th1_entry(void *parameter)
   {
     while(1)
     {
     rt_thread_mdelay(1000);
     rt_sem_take(sem1, RT_WAITING_FOREVER);
     flags++;
     if(flags==100)
         flags=0;
     rt_kprintf("th1_entry [%d]\n",flags);
     rt_sem_release(&sem2);

     }
   }
 //线程2的入口函数
 void th2_entry(void *parameter)
{
     while(1)
     {
     rt_thread_mdelay(2000);
     rt_sem_take(&sem2, RT_WAITING_FOREVER);
     if(flags>0)
         flags--;
     rt_kprintf("th2_entry [%d]\n",flags);
     rt_sem_release(sem1);

     }
}

int main(void)
{
    //动态信号量的创建sem1
    sem1=rt_sem_create("sem1", 1, RT_IPC_FLAG_FIFO);
    if(sem1==RT_NULL)
    {
        LOG_E("rt_sem_create failed...\n");
        return -RT_ENOMEM;
    }
        LOG_D("rt_sem_create successed...\n");

  //静态信号量的创建sem2
    int ret=0;
    ret=rt_sem_init(&sem2, "sem2", 0, RT_IPC_FLAG_FIFO);
    if(ret<0)
    {
        LOG_E("rt_sem_init failed...\n");
        return -RT_ENOMEM;
    }
        LOG_D("rt_sem_init successed...\n");

        //线程1的创建
    th1=rt_thread_create("th1", th1_entry, NULL, 512, 20, 5);
    if(th1==RT_NULL)
    {
        LOG_E("th1 rt_thread_create failed...\n");
         return -RT_ENOMEM;
    }
        LOG_D("th1 rt_thread_create successed...\n");

        //线程2的创建
     th2=rt_thread_create("th2", th2_entry, NULL, 512, 20, 5);
     if(th1==RT_NULL)
     {
        LOG_E("th2 rt_thread_create failed...\n");
        return -RT_ENOMEM;
     }
         LOG_D("th2 rt_thread_create successed...\n");

         rt_thread_startup(th1);
         rt_thread_startup(th2);

    return 0;
}