重庆网站制作外包,wordpress模板 黑链,提升神马seo关键词自然排名,茂名网站建设优化线程间同步
在多线程实时系统中#xff0c;一项工作的完成往往可以通过多个线程协调的方式共同来完成#xff0c;那么多个线程之间如何 “默契” 协作才能使这项工作无差错执行#xff1f;下面举个例子说明。
例如一项工作中的两个线程#xff1a;一个线程从传感器中接收…线程间同步
在多线程实时系统中一项工作的完成往往可以通过多个线程协调的方式共同来完成那么多个线程之间如何 “默契” 协作才能使这项工作无差错执行下面举个例子说明。
例如一项工作中的两个线程一个线程从传感器中接收数据并且将数据写到共享内存中同时另一个线程周期性的从共享内存中读取数据并发送去显示下图描述了两个线程间的数据传递 如果对共享内存的访问不是排他性的那么各个线程间可能同时访问它这将引起数据一致性的问题。
例如在显示线程试图显示数据之前接收线程还未完成数据的写入那么显示将包含不同时间采样的数据造成显示数据的错乱。
将传感器数据写入到共享内存块的接收线程 #1 和将传感器数据从共享内存块中读出的线程 #2 都会访问同一块内存。为了防止出现数据的差错两个线程访问的动作必须是互斥进行的一个线程对共享内存块操作完成后才允许另一个线程去操作。
同步是指按预定的先后次序进行运行线程同步是指多个线程通过特定的机制如互斥量事件对象临界区来控制线程之间的执行顺序也可以说是在线程之间通过同步建立起执行顺序的关系如果没有同步那线程之间将是无序的。
多个线程操作/访问同一块区域代码这块代码就称为临界区上述例子中的共享内存块就是临界区。 线程互斥是指对于临界区资源访问的排他性。
当多个线程都要使用临界区资源时任何时刻最多只允许一个线程去使用其它要使用该资源的线程必须等待直到占用资源者释放该资源。线程互斥可以看成是一种特殊的线程同步。
线程的同步方式有很多种其核心思想都是在访问临界区的时候只允许一个 (或一类) 线程运行。
进入 / 退出临界区的方式有很多种
调用rt_hw_interrupt_disable()进入临界区调用rt_hw_interrupt_enable()退出临界区。调用rt_enter_critical()进入临界区调用rt_exit_critical()退出临界区。
信号量
当停车场空的时候停车场的管理员发现有很多空车位此时会让外面的车陆续进入停车场获得停车位当停车场的车位满的时候管理员发现已经没有空车位将禁止外面的车进入停车场车辆在外排队等候当停车场内有车离开时管理员发现有空的车位让出允许外面的车进入停车场待空车位填满后又禁止外部车辆进入。
管理员就相当于信号量管理员手中空车位的个数就是信号量的值非负数动态变化停车位相当于公共资源临界区车辆相当于线程。车辆通过获得管理员的允许取得停车位就类似于线程通过获得信号量访问公共资源。
信号量工作机制
信号量是一种轻型的用于解决线程间同步问题的内核对象线程可以获取或释放它从而达到同步或互斥的目的。 每个信号量对象都有一个信号量值和一个线程等待队列信号量的值对应了资源的实例数目。则表示共有 5 个信号量实例资源可以被使用当信号量实例数目为零时再申请该信号量的线程就会被挂起在该信号量的等待队列上等待可用的信号量实例资源。
在 RT-Thread 中信号量控制块是操作系统用于管理信号量的一个数据结构由结构体 struct rt_semaphore 表示。另外一种 C 表达方式 rt_sem_t表示的是信号量的句柄在 C 语言中的实现是指向信号量控制块的指针。信号量控制块结构的详细定义如下
struct rt_semaphore
{struct rt_ipc_object parent; /* 继承自 ipc_object 类 */rt_uint16_t value; /* 信号量的值 */
};
/* rt_sem_t 是指向 semaphore 结构体的指针类型 */
typedef struct rt_semaphore* rt_sem_t;RT_IPC_FLAG_FIFO 属于非实时调度方式除非应用程序非常在意先来后到并且你清楚地明白所有涉及到该信号量的线程都将会变为非实时线程方可使用 RT_IPC_FLAG_FIFO否则建议采用 RT_IPC_FLAG_PRIO即确保线程的实时性。
若删除信号量时有线程正在等待信号量那么删除操作会先唤醒该线程等待线程的返回值是 - RT_ERROR然后再释放信号量的内存资源。
对于静态信号量对象它的内存空间在编译时期就被编译器分配出来放在读写数据段或未初始化数据段上只需要在使用前对它进行初始化即可。
信号量应用示例
这是一个信号量使用例程该例程创建了一个动态信号量初始化两个线程一个线程发送信号量一个线程接收到信号量后执行相应的操作。
#include rtthread.h#define THREAD_PRIORITY 25
#define THREAD_TIMESLICE 5/* 指向信号量的指针 */
static rt_sem_t dynamic_sem RT_NULL;ALIGN(RT_ALIGN_SIZE)
static char thread1_stack[1024];
static struct rt_thread thread1;
static void rt_thread1_entry(void *parameter)
{static rt_uint8_t count 0;while(1){if(count 100){count;}elsereturn;/* count 每计数 10 次就释放一次信号量 */if(0 (count % 10)){rt_kprintf(t1 release a dynamic semaphore.\n);rt_sem_release(dynamic_sem);}}
}ALIGN(RT_ALIGN_SIZE)
static char thread2_stack[1024];
static struct rt_thread thread2;
static void rt_thread2_entry(void *parameter)
{static rt_err_t result;static rt_uint8_t number 0;while(1){/* 永久方式等待信号量获取到信号量则执行 number 自加的操作 */result rt_sem_take(dynamic_sem, RT_WAITING_FOREVER);if (result ! RT_EOK){rt_kprintf(t2 take a dynamic semaphore, failed.\n);rt_sem_delete(dynamic_sem);return;}else{number;rt_kprintf(t2 take a dynamic semaphore. number %d\n ,number);}}
}/* 信号量示例的初始化 */
int semaphore_sample(void)
{/* 创建一个动态信号量初始值是 0 */dynamic_sem rt_sem_create(dsem, 0, RT_IPC_FLAG_PRIO);if (dynamic_sem RT_NULL){rt_kprintf(create dynamic semaphore failed.\n);return -1;}else{rt_kprintf(create done. dynamic semaphore value 0.\n);}rt_thread_init(thread1,thread1,rt_thread1_entry,RT_NULL,thread1_stack[0],sizeof(thread1_stack),THREAD_PRIORITY, THREAD_TIMESLICE);rt_thread_startup(thread1);rt_thread_init(thread2,thread2,rt_thread2_entry,RT_NULL,thread2_stack[0],sizeof(thread2_stack),THREAD_PRIORITY-1, THREAD_TIMESLICE);rt_thread_startup(thread2);return 0;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(semaphore_sample, semaphore sample);