1 信号量
信号量是一种用于管理线程间资源关系的内核对象,线程可以获取或释放它从而达到同步或互斥的目的;
信号量可以运用在多种场合中,形成锁,同步(多个线程可访问同一资源),资源计数等关系,也能方便的用于线程与线程,中断与线程的同步中;
1.1 semaphore 信号量结构体
//rtdef.h
#ifdef RT_USING_SEMAPHORE
struct rt_semaphore
{
struct rt_ipc_object parent; /**< inherit from ipc_object */
rt_uint16_t value; /**< value of semaphore. */
};
typedef struct rt_semaphore *rt_sem_t;
#endif
struct rt_ipc_object
{
struct rt_object parent; /**< inherit from rt_object */
rt_list_t suspend_thread; /**< threads pended on this resource */
};
struct rt_object
{
char name[RT_NAME_MAX]; /**< name of kernel object */
rt_uint8_t type; /**< type of kernel object */
rt_uint8_t flag; /**< flag of kernel object */
#ifdef RT_USING_MODULE
void *module_id; /**< id of application module */
#endif
rt_list_t list; /**< list node of kernel object */
};
typedef struct rt_object *rt_object_t; /**< Type for kernel objects. */
//IPC flags and control command definitions
#define RT_IPC_FLAG_FIFO 0x00 /**< FIFOed IPC. 先进先出 */
#define RT_IPC_FLAG_PRIO 0x01 /**< PRIOed IPC. 优先级 */
#define RT_IPC_CMD_UNKNOWN 0x00 /**< unknown IPC command */
#define RT_IPC_CMD_RESET 0x01 /**< reset IPC object */
#define RT_WAITING_FOREVER -1 /**< Block forever until get resource. */
#define RT_WAITING_NO 0 /**< Non-block. */
1.2 rt_sem_create 创建信号量
这个信号量的创建函数还挺简单的嘞,这个信号量信息不多看来很简单;事后也确实很简单;
信号量的flag建议采用RT_IPC_FLAG_PRIO,可以保证线程的实时性;RT_IPC_FLAG_FIFO属于非实时调度,实时性不如优先级flag方式;
//ipc.c
rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag)
{
rt_sem_t sem;
RT_DEBUG_NOT_IN_INTERRUPT;
/* allocate object */
sem = (rt_sem_t)rt_object_allocate(RT_Object_Class_Semaphore, name);
if (sem == RT_NULL)
return sem;
/* init ipc object */
rt_ipc_object_init(&(sem->parent));
/* set init value */
sem->value = value;
/* set parent */
sem->parent.parent.flag = flag;
return sem;
}
RTM_EXPORT(rt_sem_create);
1.3 rt_sem_delete 删除信号量
//ipc.c
rt_err_t rt_sem_delete(rt_sem_t sem)
{
RT_DEBUG_NOT_IN_INTERRUPT;
RT_ASSERT(sem != RT_NULL);
/* wakeup all suspend threads */
rt_ipc_list_resume_all(&(sem->parent.suspend_thread));
/* delete semaphore object */
rt_object_delete(&(sem->parent.parent));
return RT_EOK;
}
//在rt_object_delete(rt_object_t object)函数中,主要执行了两个操作,一个是rt_list_remove(&object->list),一个是RT_KERNEL_FREE(object);
//object是指针,作为变量传递赋值的时候,可不等价于传递地址了吗?
//malloc函数在分配地址的时候,会自动先拿出4字节存储分配的内存大小,然后把后面的地址返回;
//所以free内存的时候,不需要传入内存大小,free也知道需要释放的内存大小;
1.4 rt_sem_take 获取信号量
//ipc.c 如果当前信号量值大于0,那么信号量值减1,然后就返回继续执行当前线程函数;说明当前线程使用了一个信号量资源;
// 如果当前信号量值为0,说明没有信号量资源;那就根据time值判断是否等待;
// 如果不等待则直接返回超时函数;如果等待,则将当前线程悬起到suspend_thread,等到有信号量资源的时候再释放;
rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time)
{
register rt_base_t temp;
struct rt_thread *thread;
RT_ASSERT(sem != RT_NULL);
RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(sem->parent.parent)));
/* disable interrupt */
temp = rt_hw_interrupt_disable();
RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s take sem:%s, which value is: %d\n",
rt_thread_self()->name,
((struct rt_object *)sem)->name,
sem->value));
if (sem->value > 0)
{
/* semaphore is available */
sem->value --;
/* enable interrupt */
rt_hw_interrupt_enable(temp);
}
else
{
/* no waiting, return with timeout */
if (time == 0)
{
rt_hw_interrupt_enable(temp);
return -RT_ETIMEOUT;
}
else
{
/* current context checking */
RT_DEBUG_IN_THREAD_CONTEXT;
/* semaphore is unavailable, push to suspend list */
/* get current thread */
thread = rt_thread_self();
/* reset thread error number */
thread->error = RT_EOK;
RT_DEBUG_LOG(RT_DEBUG_IPC, ("sem take: suspend thread - %s\n",
thread->name));
/* suspend thread */
rt_ipc_list_suspend(&(sem->parent.suspend_thread),
thread,
sem->parent.parent.flag);
/* has waiting time, start thread timer */
if (time > 0)
{
RT_DEBUG_LOG(RT_DEBUG_IPC, ("set thread:%s to timer list\n",
thread->name));
/* reset the timeout of thread timer and start it */
rt_timer_control(&(thread->thread_timer),
RT_TIMER_CTRL_SET_TIME,
&time);
rt_timer_start(&(thread->thread_timer));
}
/* enable interrupt */
rt_hw_interrupt_enable(temp);
/* do schedule */
rt_schedule();
if (thread->error != RT_EOK)
{
return thread->error;
}
}
}
RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(sem->parent.parent)));
return RT_EOK;
}
RTM_EXPORT(rt_sem_take);
1.5 rt_sem_release 释放信号量
//ipc.c 如果suspend_thread中有等待线程,那么将其恢复,然后rt_schedule,
// 让另外一个等待信号量的suspend_thread有了执行权就相当于这里的信号量加1了;
// if suspend_thread中没有等待线程,那么当前线程释放了信号量,就把信号量值加1;
rt_err_t rt_sem_release(rt_sem_t sem)
{
register rt_base_t temp;
register rt_bool_t need_schedule;
RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(sem->parent.parent)));
need_schedule = RT_FALSE;
/* disable interrupt */
temp = rt_hw_interrupt_disable();
RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s releases sem:%s, which value is: %d\n",
rt_thread_self()->name,
((struct rt_object *)sem)->name,
sem->value));
if (!rt_list_isempty(&sem->parent.suspend_thread))
{
/* resume the suspended thread */
rt_ipc_list_resume(&(sem->parent.suspend_thread));
need_schedule = RT_TRUE;
}
else
sem->value ++; /* increase value */
/* enable interrupt */
rt_hw_interrupt_enable(temp);
/* resume a thread, re-schedule */
if (need_schedule == RT_TRUE)
rt_schedule();
return RT_EOK;
}
RTM_EXPORT(rt_sem_release);
1.6 gitee
rtthread_f1demo: 将rtthread nano3.0.3版本移植到stm32f1上; (gitee.com)
2 小结
写demo的时候应该单独开个文件来写的,这样就不用每次都修改main函数了,调用函数例程就叫xx_sample把;
标签:rt,信号量,parent,thread,object,rtthread,STM32,RT,sem From: https://www.cnblogs.com/caesura-k/p/17553370.html