线程间同步
在多线程实时系统中,一项工作的完成往往可以通过多个线程协调的方式共同来完成,而通过这三种方式:信号量、互斥量、事件集可以保证多个线程之间同步。
线程的同步方式有很多种,其核心思想都是:在访问临界区的时候只允许一个 (或一类) 线程运行。进入 / 退出临界区的方式有很多种:
1)调用 rt_hw_interrupt_disable() 进入临界区,调用 rt_hw_interrupt_enable() 退出临界区;详见《中断管理》的全局中断开关内容。
2)调用 rt_enter_critical() 进入临界区,调用 rt_exit_critical() 退出临界区。
线程同步是指多个线程通过特定的机制(如互斥量,事件对象,临界区)来控制线程之间的执行顺序
1.信号量
以生活中的停车场为例来理解信号量的概念:
①当停车场空的时候,停车场的管理员发现有很多空车位,此时会让外面的车陆续进入停车场获得停车位;
②当停车场的车位满的时候,管理员发现已经没有空车位,将禁止外面的车进入停车场,车辆在外排队等候;
③当停车场内有车离开时,管理员发现有空的车位让出,允许外面的车进入停车场;待空车位填满后,又禁止外部车辆进入。
在此例子中,管理员就相当于信号量,管理员手中空车位的个数就是信号量的值(非负数,动态变化);停车位相当于公共资源(临界区),车辆相当于线程。车辆通过获得管理员的允许取得停车位,就类似于线程通过获得信号量访问公共资源。
1.信号量机制
信号量是一种轻型的用于解决线程间同步问题的内核对象,线程可以获取或释放它,从而达到同步或互斥的目的。
2.信号量控制块
信号量控制块是操作系统用于管理信号量的一个数据结构
struct rt_semaphore
{
struct rt_ipc_object parent; //继承ipc_object结构体{rt_object(name、type、flag); suspend_thread}
rt_uint16_t value; //信号量的数值(例如空车位数量)
};
typedef struct rt_semaphore *rt_sem_t;
第一个parent rt_ipc_object
{struct rt_object parent;
rt_list_t suspend_thread;
}
第二个parent rt_object
{
char name[RT_NAME_MAX];
rt_uint8_t type;
rt_uint8_t flag;
}
3.信号量管理方式
Kernel中的 ipc.c
函数顺序按照ipc.c中顺序(内核代码顺序是按照创作顺序书写的)
1.判断是否使用信号量
#ifdef RT_USING_SEMAPHORE
信号量的开端,在rtconfig.h中是否宏定义了,才可使用信号量函数(一般都是定义的)
2.初始化和脱离
初始化(多是对系统静态句柄操作)
rt_err_t rt_sem_init(rt_sem_t sem,//信号量对象的句柄(停车场地址)
const char *name,//信号量名称(停车场名字)
rt_uint32_t value,//信号量初始值(停车场车位数量)
rt_uint8_t flag)//信号量标志等待线程队列RT_IPC_FLAG_FIFO(按顺序) 或 RT_IPC_FLAG_PRIO(按优先级)(排队顺序还是优先级顺序进出)
{
RT_ASSERT(sem != RT_NULL);//信号量对象的句柄是否存在
/* init object */
rt_object_init(&(sem->parent.parent), RT_Object_Class_Semaphore, name);
//sem->parent.parent的初始化(见1.2信号量控制块)
/* init ipc object */
rt_ipc_object_init(&(sem->parent));
//sem->parent的初始化(见1.2信号量控制块)
/* set init value */
sem->value = value;//赋值
/* set parent */
sem->parent.parent.flag = flag;//设置标志位RT_IPC_FLAG_FIFO(按顺序) 或 RT_IPC_FLAG_PRIO(按优先级)
return RT_EOK;
}
RTM_EXPORT(rt_sem_init);
脱离(内存继续存在,所以是脱离-内存还存在)
有初始化必有脱离
rt_err_t rt_sem_detach(rt_sem_t sem)
{
/* parameter check */
RT_ASSERT(sem != RT_NULL);//信号量对象的句柄是否存在
RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore);//rt_object名字是否为信号量并返回对象类型
RT_ASSERT(rt_object_is_systemobject(&sem->parent.parent));
//判断对象是否为系统对象
/* wakeup all suspend threads */
rt_ipc_list_resume_all(&(sem->parent.suspend_thread));
//唤醒挂起线程(为使用信号量排队的线程),让他们返回失败(别等了,停车场关门了)
/* detach semaphore object */
rt_object_detach(&(sem->parent.parent));//信号量对象从内核对象管理器中脱离
return RT_EOK;
}
RTM_EXPORT(rt_sem_detach);
3.创建和删除
创建
和初始化差别:没有已存在的信号量句柄,要自己创建,要自己给内存
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