一、介绍信号量
信号量是一种轻型的用于解决线程间同步问题的内核对象,线程可以获取或释放它,从而达到同步或互斥的目的。
每个信号量对象都有一个信号量值和一个线程等待队列,信号量的值对应了信号量对象的实例数目、资源数目,假如信号量值为 5,则表示共有 5 个信号量实例(资源)可以被使用,当信号量实例数目为零时,再申请该信号量的线程就会被挂起在该信号量的等待队列上,等待可用的信号量实例(资源)。其实所谓的资源,简单举个例子说就是对某个变量的操作权。信号量就是有传递信息的作用,“量”就是是否还有可以操作某个资源(比如变量,也是一个资源)的权限,比如读写和赋值等。
跟定时器和创建线程一样,都是一个套路,对信号量的操作也包含创建 / 初始化信号量、获取信号量、释放信号量、删除 / 脱离信号量,记住删除只能对应动态信号量,因为删除是连创建信号量时分配的内存一起删除,而静态只是脱离,不能再使用这个信号量,不能删除占用的内存。如果当前信号量的值是0,再有线程去申请,就会挂在在该链表上等待新的信号量数值,如果数值大于0,就会唤醒在该等待队列的线程,至于唤醒是优先级线程唤醒还是先进先出唤醒,要看创建线程时是设置的什么属性,举例子时我会注释出来。
三、信号量的使用示例
thread1优先级比较高会先执行,正常情况下执行rt_kprintf("thread1test1\r\n")后又延时了时间应该切换到thread2执行rt_kprintf("thread2test1\r\n")打印,但是实际不会,因为到thread2时信号量的值为0了,获取不到资源所以执行不了,这就是信号量同步的作用。(Note:rt_kprintf是thread的API,默认输出到STM32F103C8T6的UART1)
#include "board.h" //头文件合集
#include <stdio.h>
struct rt_thread thread1;
struct rt_thread thread2;
static rt_sem_t sem = RT_NULL;
rt_uint8_t thread1_stack[512]={0};
rt_uint8_t thread2_stack[512]={0};
static void thread1_callback(void *parameter)
{
rt_err_t result = RT_EOK;
while(1)
{
//注释掉信号量的获取和释放,两个线程的打印就会交替进行
result = rt_sem_take(sem,RT_WAITING_FOREVER);//信号量值-1
if(result != RT_EOK)
{
return ;
}
rt_kprintf("thread1test1\r\n");
rt_thread_delay(300);//延时300ms,让thread2可以去运行
rt_kprintf("thread1test2\r\n");
rt_sem_release(sem); //释放信号量,值+1
}
}
static void thread2_callback(void *parameter)
{
rt_err_t result = RT_EOK;
while(1)
{
result = rt_sem_take(sem,RT_WAITING_FOREVER);
if(result != RT_EOK)
{
return ;
}
rt_kprintf("thread2test1\r\n");
rt_thread_delay(300);//延时300ms,让thread1可以去运行
rt_kprintf("thread2test2\r\n");
rt_sem_release(sem);
}
}
int main(void)
{
/*T_IPC_FLAG_FIFO的意思是信号量值是0时,线程谁先等待等信号值不为0时就先唤醒谁
1是初值为1*/
sem = rt_sem_create("sem_demo",1,RT_IPC_FLAG_FIFO);
rt_thread_init(&thread1,
"thread1",
thread1_callback,
NULL,
&thread1_stack[0],
sizeof(thread1_stack),
7,
5);
/*5是时间片,作用是当有相同优先级的线程时,最大执行时间是5 tick
如果线程毁掉函数执行时间少于5 tick,也会提前返回,切换带到下一个线程
如果5 tick还没执行完也会切换到下一个线程 */
rt_thread_init(&thread2,
"thread2",
thread2_callback,
RT_NULL,
&thread2_stack[0],
sizeof(thread2_stack),
8,
5);
//开启两个线程
rt_thread_startup(&thread1);
rt_thread_startup(&thread2);
return 0;
}
加上信号量有不同的效果,看打印。有信号量是执行完thread1后释放信号量thread2检测到信号量值不为0执行后面的打印。无信号量是thread1和thread2轮流执行,交替打印。