目录

一  RT-Thread 信号量

二  RT-Thread 互斥量

三  RT-Thread 事件标志组

四  RT-Thread 邮箱

五  RT-Thread 消息队列


一  RT-Thread 信号量

1. 信号量相关函数

创建信号量

/** @param  name:信号量名称

* @param  value:信号量初始值

* @param  flag:信号量标志,可取RT_IPC_FLAG_FIFO或者RT_IPC_FLAG_PRIO
  * @retval  创建成功返回创建的信号量控制块指针;否则返回RT_NULL
  */

rt_sem_t rt_sem_create (const char* name,rt_uint32_t value,rt_uint8_t flag);

删除信号量

/** @param  sem:rt_sem_create创建处理的信号量对象
  * @retval  RT_EOK
  */

rt_err_t rt_sem_delete (rt_sem_t sem);

初始化静态信号量

/** @param  sem:信号量对象的句柄

* @param  name:信号量名称

* @param  value:信号量初始值

* @param  flag:信号量标志,可取RT_IPC_FLAG_FIFO或者RT_IPC_FLAG_PRIO
  * @retval  RT_EOK
  */

rt_err_t rt_sem_init (rt_sem_t sem, const char* name, rt_uint32_t value, rt_uint8_t flag);

脱离信号量

/** @brief   让信号量对象从内核对象管理器中移除掉

* @param  sem:rt_sem_create创建处理的信号量对象
  * @retval  RT_EOK
  */

rt_err_t rt_sem_detach (rt_sem_t sem);

获取信号量

/** @brief   线程通过获取信号量来获得信号量资源实例,当信号量值大于零时,线程将获得信号
  *                量,并且相应的信号量值都会减1

* @param  sem:信号量对象的句柄

* @param  time:指定的等待时间,单位是操作系统时钟节拍
  * @retval  成功获得信号量返回RT_EOK;超时依然未获得信号量返回-RT_ETIMEOUT;其他错误返
  *                回-RT_ERROR。
  */

rt_err_t rt_sem_take (rt_sem_t sem, rt_int32_t time);

无等待获取信号量

/** @brief   这个函数与rt_sem_take(sem, 0) 的作用相同

* @param  sem:信号量对象的句柄
  * @retval  成功获取信号量返回RT_EOK;否则返回RT_ETIMEOUT。
  */

rt_err_t rt_sem_trytake(rt_sem_t sem);

释放信号量

/** @brief   当线程完成资源的访问后,应尽快释放它持有的信号量,使得其他线程能获得该信号量

* @param  sem:信号量对象的句柄
  * @retval  RT_EOK
  */

rt_err_t rt_sem_release(rt_sem_t sem);

2.  创建一个静态信号量

/* 信号量控制块 */
static struct rt_semaphore sem;/* 初始化信号量,初始值是1 */
result = rt_sem_init(&sem, "sem", 1, RT_IPC_FLAG_FIFO);

3. 创建一个动态信号量

/* 指向信号量的指针 */
rt_sem_t sem = RT_NULL;/* 创建一个信号量,初始值是1 */
sem = rt_sem_create("sem", 1, RT_IPC_FLAG_FIFO);

4. 通过信号量访问共享资源,不推荐,可能会导致优先级翻转

rt_sem_take(sem, RT_WAITING_FOREVER);/* 试图持有一个信号量,如果不成功则一直等待知道成功 */*
访问共享资源*
rt_sem_release(sem); /* 释放一次信号量 */

5. 使用信号量进行中断与线程同步

void USART1_IRQHandler(void)
{接受到串口数据rt_sem_release(sem); /* 释放信号量 */
}void thread0(void* arg)
{while(1){rt_sem_take(sem); /* 获取信号量 */处理串口数据}
}

二  RT-Thread 互斥量

1. 互斥量相关函数

创建互斥量

/**

* @brief   完成对该互斥量控制块的初始化工作

* @param  name:互斥量的名称

* @param  flag:互斥量标志,可取RT_IPC_FLAG_FIFO 与 RT_IPC_FLAG_PRIO
  * @retval  创建成功返回指向互斥量的互斥量句柄;否则返回RT_NULL
  */

rt_mutex_t rt_mutex_create (const char* name, rt_uint8_t flag);

删除互斥量

/** @param  mutex:互斥量对象的句柄
  * @retval  RT_EOK
  */

rt_err_t rt_mutex_delete (rt_mutex_t mutex);

初始化静态互斥量

/**

* @param  mutex:互斥量对象的句柄

* @param  name:互斥量的名称

* @param  flag:互斥量标志,可取RT_IPC_FLAG_FIFO 与 RT_IPC_FLAG_PRIO
  * @retval  RT_EOK
  */

rt_err_t rt_mutex_init (rt_mutex_t mutex, const char* name, rt_uint8_t flag);

脱离互斥量

/** @brief:脱离互斥量将把互斥量对象从内核对象管理器中删除

* @param  mutex:互斥量对象的句柄
  * @retval  RT_EOK
  */

rt_err_t rt_mutex_detach (rt_mutex_t mutex);

获取互斥量

/** @brief:线程通过互斥量申请服务获取互斥量的所有权,如果互斥量已经被当前线程线程控制,则该互斥                       量的持有计数加1,

* @param  mutex:互斥量对象的句柄

* @param  time:指定等待的时间
  * @retval  成功获得互斥量返回RT_EOK;超时返回-RT_ETIMEOUT;其他返回-RT_ERROR
  */

rt_err_t rt_mutex_take (rt_mutex_t mutex, rt_int32_t time);

释放互斥量

/** @brief:使用该函数接口时,只有已经拥有互斥量控制权的线程才能释放它,每释放一次该互斥量,它的持                     有计数就减1,当该互斥量的持有计数为零时,它变为可用。

* @param  mutex:互斥量对象的句柄
  * @retval  RT_EOK
  */

rt_err_t rt_mutex_release(rt_mutex_t mutex);

2. 互斥量注意事项

  • 需要切记的是互斥量不能在中断服务例程中使用。
  • 可以防止优先级翻转
  • 在获得互斥量之后,应该尽快释放互斥量
  • 持有互斥量的过程中,不得再调用 rt_thread_control()等函数接口更改持有互斥量线程的优先级
  • 互斥量可用于对单个硬件资源进行保护,比如多个线程需要调用串口1发送数据,则可以在调用串口时使用互斥量

3. 创建静态互斥量

/* 互斥量控制块*/
static rt_mutex mutex;/* 初始化互斥量*/
rt_mutex_create(&mutex, "mutex", RT_IPC_FLAG_FIFO);

4.创建动态互斥量

/* 指向互斥量的指针 */
static rt_mutex_t mutex = RT_NULL;/* 创建互斥锁 */
mutex = rt_mutex_create("mutex", RT_IPC_FLAG_FIFO);

5. 使用互斥量访问共享资源(例如串口),推荐使用该种方式访问共享资源,而不是信号量的方式。

void usart_send_buf(uint8_t *buf,uint32_t len)
{rt_mutex_take(mutex, RT_WAITING_FOREVER); /*  获取互斥量 */调用硬件串口资源输出字符rt_mutex_release(mutex);
}

三  RT-Thread 事件标志组

1. 事件标志组相关函数

创建事件

/**

* @brief   对事件控制块进行基本的初始化

* @param  name:事件的名称

* @param  flag:事件标志,可取RT_IPC_FLAG_FIFO 与 RT_IPC_FLAG_PRIO
  * @retval  创建成功返回事件对象的句柄;创建失败返回RT_NULL
  */

rt_event_t rt_event_create (const char* name, rt_uint8_t flag);

删除事件

/** @param  event:事件对象的句柄
  * @retval  RT_EOK
  */

rt_err_t rt_event_delete (rt_event_t event);

初始化事件

/**

* @param  event:事件对象的句柄

* @param  name:事件的名称

* @param  flag:事件标志,可取RT_IPC_FLAG_FIFO 与 RT_IPC_FLAG_PRIO
  * @retval  RT_EOK
  */

rt_err_t rt_event_init(rt_event_t event, const char* name, rt_uint8_t flag);

脱离事件

/** @brief:脱离事件是将事件对象从内核对象管理器中删除

* @param  mutex:事件对象的句柄
  * @retval  RT_EOK
  */

rt_err_t rt_event_detach(rt_event_t event);

接受事件

/** @brief:内核使用32位的无符号整型数来标识事件,它的每一位代表一个事件,因此一个事件对 象可同时等                     待接收32个事件。当用户调用这个接口时,首先根据set参数和接收选项来判断它要接收的事件是否                     发生,如果已经发生,则根据参数option上是否设置有RT_EVENT_FLAG_CLEAR来决定是否重置

事件的相应标志位

* @param  event:事件对象的句柄

* @param  set:接收线程感兴趣的事件

* @param  option:接收选项

* @param  timeout:指定超时时间

* @param  recved:指向收到的事件
  * @retval  正确接收返回RT_EOK,超时返回-RT_TIMEOUT,其他返回-RT_ERROR
  */

rt_err_t rt_event_recv(rt_event_t event, rt_uint32_t set, rt_uint8_t option,rt_int32_t timeout, rt_uint32_t* recved);

发送事件

/** @brief:可以发送一个或多个事件

* @param  event:事件对象的句柄

* @param  set:接收线程感兴趣的事件
  * @retval  RT_EOK
  */

rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set);

2. 创建静态事件

/* 事件控制块 */
static struct rt_event event;
/* 初始化事件对象 */
rt_event_init(&event, "event", RT_IPC_FLAG_FIFO);

3. 创建动态事件

/* 指向事件的地址指针 */
rt_event_t event = RT_NULL;
/* 创建事件 */
event = rt_event_create( "event", RT_IPC_FLAG_FIFO);

4. 用于中断与线程的同步

void USART1_IRQHandler(void)
{接受到串口数据rt_event_send(event,0x1); /*发送事件 */
}void thread0(void* arg)
{rt_uint32_t recved;while(1){/*  等待接收事件标志 */rt_event_recv(test_event,    /*  事件对象句柄 */0x1,                   /*  接收线程感兴趣的事件 */RT_EVENT_FLAG_AND|RT_EVENT_FLAG_CLEAR,/*  接收选项 */RT_WAITING_FOREVER,    /*  指定超时事件, 一直等 */&recved);              /*  指向接收到的事件 */...处理串口数据}
}

四  RT-Thread 邮箱

1. 邮箱相关函数

创建邮箱

/**

* @brief   创建动态邮箱

* @param  name:邮箱的名称

* @param  size:邮箱容量

* @param  flag:邮箱标志,可取RT_IPC_FLAG_FIFO 与 RT_IPC_FLAG_PRIO
  * @retval  创建成功返回邮箱对象的句柄;否则返回-RT_NULL
  */

rt_mailbox_t rt_mb_create (const char* name, rt_size_t size, rt_uint8_t flag);

删除邮箱

/**

* @param  mutex:邮箱对象的句柄
  * @retval  RT_EOK
  */

rt_err_t rt_mb_delete (rt_mailbox_t mb);

初始化邮箱

/**

* @brief   创建静态邮箱

* @param  mb:邮箱对象的句柄

* @param  name:邮箱的名称

* @param  msgpool:缓冲区指针

* @param  size:邮箱容量

* @param  flag:邮箱标志,可取RT_IPC_FLAG_FIFO 与 RT_IPC_FLAG_PRIO
  * @retval  RT_EOK
  */

rt_err_t rt_mb_init(rt_mailbox_t mb, const char* name, void* msgpool,rt_size_t size, rt_uint8_t flag)

邮箱脱离

/**

* @brief:脱离邮箱将把邮箱对象从内核对象管理器中删除

* @param  mb:邮箱对象的句柄
  * @retval  RT_EOK
  */

rt_err_t rt_mb_detach(rt_mailbox_t mb);

发送邮件

/**

* @brief:发送的邮件可以是32位任意格式的数据,一个整型值或者一个指向缓冲区的指针

* @param  mb:邮箱对象的句柄

* @param  value:邮件内容
  * @retval  发送成功返回RT_EOK;如果邮箱已经满了,返回-RT_EFULL。
  */

rt_err_t rt_mb_send (rt_mailbox_t mb, rt_uint32_t value);

等待方式发送邮件

/**

* @brief:发送邮件,如果邮箱已满,则等待timeout个系统时间

* @param  mb:邮箱对象的句柄

* @param  value:邮件内容

* @param  timeout:超时时间
  * @retval  发送成功返回RT_EOK;如果设置的时间超时依然未发送成功,返回-RT_ETIMEOUT,其他情况返回-                                RT_ERROR。
  */

rt_err_t rt_mb_send_wait (rt_mailbox_t mb, rt_uint32_t value, rt_int32_t timeout);

接受邮件

/**

* @param  mb:邮箱对象的句柄

* @param  value:邮件内容

* @param  timeout:超时时间
  * @retval  成功收到返回RT_EOK,超时返回-RT_ETIMEOUT,其他返回-RT_ERROR
  */

rt_err_t rt_mb_recv (rt_mailbox_t mb, rt_uint32_t* value, rt_int32_t timeout);

2. 创建静态邮箱

/* 邮箱控制块 */
static struct rt_mailbox mb;
/* 用于放邮件的内存池 */
static char mb_pool[128];/* 初始化一个mailbox */
rt_mb_init(&mb,"mbt",              /* 名称是mbt */&mb_pool[0],       /* 邮箱用到的内存池是mb_pool */sizeof(mb_pool)/4, /* 大小是mb_pool/4,因为每封邮件的大小是4字节 */RT_IPC_FLAG_FIFO); /* 采用FIFO方式进行线程等待 */

3 创建动态邮箱

/*  定义邮箱控制块 */
static rt_mailbox_t mb = RT_NULL;/*  创建一个邮箱 */
test_mail = rt_mb_create("test_mail",       /*  邮箱名字 */10,               /*  邮箱大小 */RT_IPC_FLAG_FIFO);/*  信号量模式 FIFO(0x00)*/
if (test_mail != RT_NULL)rt_kprintf(" 邮箱创建成功!\n\n");

4. 发送与接收邮件

static char mb_str[] = "I'm a mail!";void thread0(void* parameter)
{while (1){/* 发送mb_str1地址到邮箱中 */rt_mb_send(&mb, (rt_uint32_t)&mb_str[0]);}
}void thread1(void* parameter)
{unsigned char* str;while (1){/* 从邮箱中收取邮件 */if (rt_mb_recv(&mb, (rt_uint32_t*)&str, RT_WAITING_FOREVER)== RT_EOK){/* 处理邮箱内容 */}}
}

五  RT-Thread 消息队列

1. 消息队列相关函数

创建消息队列

/**

* @brief   创建动态消息队列

* @param  name:消息队列的名称

* @param  msg_size:消息队列中一条消息的最大长度

* @param  max_msgs:消息队列的最大容量

* @param  flag:消息队列标志,可取RT_IPC_FLAG_FIFO 与 RT_IPC_FLAG_PRIO
  * @retval  成功创建返回消息队列对象的句柄;否则返回-RT_ERROR
  */

rt_mq_t rt_mq_create(const char* name, rt_size_t msg_size, rt_size_t max_msgs, rt_uint8_t flag);

删除消息队列

/**

* @param  mq:消息队列对象的句柄
  * @retval  RT_EOK
  */

rt_err_t rt_mq_delete(rt_mq_t mq);

初始化消息队列

/**

* @brief   创建静态消息队列

* @param  mq:指向静态消息队列对象的句柄

* @param  name:消息队列的名称

* @param  msgpool:用于存放消息的缓冲区

* @param  msg_size:消息队列中一条消息的最大长度

* @param  pool_size:存放消息的缓冲区大小

* @param  flag:消息队列标志,可取RT_IPC_FLAG_FIFO 与 RT_IPC_FLAG_PRIO
  * @retval  RT_EOK
  */

rt_err_t rt_mq_init(rt_mq_t mq, const char* name, void *msgpool, rt_size_t msg_size, rt_size_t pool_size,rt_uint8_t flag);

消息队列脱离

/**

* @brief:脱离消息队列将使消息队列对象被从内核对象管理器中删除

* @param  mq:指向静态消息队列对象的句柄
  * @retval  RT_EOK
  */

rt_err_t rt_mq_detach(rt_mq_t mq);

发送消息

/**

* @brief:发送的邮件可以是32位任意格式的数据,一个整型值或者一个指向缓冲区的指针

* @param  mq:消息队列对象的句柄

* @param  buffer:消息内容

* @param  size:消息大小
  * @retval  发送成功返回RT_EOK;如果邮箱已经满了,返回-RT_EFULL。
  */

rt_err_t rt_mq_send (rt_mq_t mq, void* buffer, rt_size_t size);

发送紧急消息

/**

* @brief:发送邮件,如果邮箱已满,则等待timeout个系统时间

* @param  mq:消息队列对象的句柄

* @param  buffer:消息内容

* @param  size:消息大小
  * @retval  发送成功返回RT_EOK,如果消息队列已满返回-RT_EFULL
  */

rt_err_t rt_mq_urgent(rt_mq_t mq, void* buffer, rt_size_t size);

接受消息

/**

* @param  mq:消息队列对象的句柄

* @param  buffer:用于接收消息的数据块

* @param  size:消息大小

* @param  timeout:指定的超时时间
  * @retval  成功收到返回RT_EOK,超时返回-RT_ETIMEOUT,其他返回-RT_ERROR
  */

rt_err_t rt_mq_recv (rt_mq_t mq, void* buffer, rt_size_t size, rt_int32_t timeout);

2. 创建静态消息队列

/* 消息队列控制块 */
static struct rt_messagequeue mq;
/* 消息队列中用到的放置消息的内存池 */
static char msg_pool[2048];/* 初始化消息队列 */
rt_mq_init(&mq, "mqt",&msg_pool[0],        /* 内存池指向msg_pool */128 - sizeof(void*), /* 每个消息的大小是 128 - void* */sizeof(msg_pool),    /* 内存池的大小是msg_pool的大小 */RT_IPC_FLAG_FIFO);   /* 如果有多个线程等待,按照FIFO的方法分配消息 */

3  创建动态消息队列

/*  定义消息队列控制块 */rt_mq_t mq = RT_NULL;
/* 创建一个消息队列 */
test_mq = rt_mq_create("test_mq",/*  消息队列名字 */40, /*  消息的最大长度 */20, /*  消息队列的最大容量 */RT_IPC_FLAG_FIFO);/*  队列模式 FIFO(0x00)*/
if (test_mq != RT_NULL)rt_kprintf(" 消息队列创建成功!\n\n");

4 使用消息队列收发数据

void thread0(void* parameter)
{char buf[] = "this is message No.x";while (1){/* 发送消息到消息队列中 */result = rt_mq_send(&mq, &buf[0], sizeof(buf));if ( result == -RT_EFULL){/* 消息队列满 */rt_kprintf("message queue full, delay 1s\n");}}
}void thread1(void* parameter)
{char buf[128];while (1){/* 从消息队列中接收消息 */if (rt_mq_recv(&mq, &buf[0], sizeof(buf), RT_WAITING_FOREVER) == RT_EOK){/* 处理消息 */rt_kprintf("thread1: recv a msg, the content:%s\n", buf);}}
}

RT-Thread 线程同步及通信 -- 信号量、互斥量、事件、邮箱、消息队列相关推荐

  1. VxWorks中的任务间通信(信号量、共享内存、消息队列、管道、信号、事件、套接字socket)

    文章目录 信号量 共享内存 消息队列 管道 信号 事件 套接字(socket) 总结 VxWorks5.5中,为了保证各个独立的任务可以协同工作,提供了一整套任务间的通信机制,主要包括信号量,共享内存 ...

  2. 线程同步(临界区、互斥量、事件、信号量)

    1.为什么线程要同步? #include<windows.h> #include<iostream> using namespace std; DWORD WINAPI Thr ...

  3. C#线程同步(3)- 互斥量 Mutex

    什么是Mutex "mutex"是术语"互相排斥(mutually exclusive)"的简写形式,也就是互斥量.互斥量跟临界区中提到的Monitor很相似, ...

  4. 线程同步,通信与虚方法

    线程同步,通信与虚方法 目录 线程同步,通信与虚方法 进程同步,通信 事件event 旗语semaphore 信箱mailbox 虚方法 实例理解 将子类句柄赋值成父类句柄 将父类句柄赋值成子类句柄 ...

  5. C#笔记20:多线程之线程同步中的信号量AutoResetEvent和ManualResetEvent

    C#笔记20:多线程之线程同步中的信号量AutoResetEvent和ManualResetEvent 本章概要: 1:终止状态和非终止状态 2:AutoResetEvent和ManualResetE ...

  6. 信号量 互斥量 条件变量

    原文:https://blog.csdn.net/qq_32646795/article/details/78221005 本文打算写一些和锁有关的东西,谈一谈我对锁的原理和实现的理解,主要包含以下方 ...

  7. Linux进程通信的四种方式——共享内存、信号量、无名管道、消息队列|实验、代码、分析、总结

    Linux进程通信的四种方式--共享内存.信号量.无名管道.消息队列|实验.代码.分析.总结 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须 ...

  8. 【Linux Program】信号量、共享内存和消息队列

    系列文章: 文件操作 数据管理 进程和信号 POSIX 线程 进程间通信:管道 信号量共享内存和消息队列 套接字 文章目录 1. 信号量 1.1 信号量的定义 1.2 Linux 的信号量机制 1.3 ...

  9. Win32多线程编程(3) — 线程同步与通信

    一.线程间数据通信 系统从进程的地址空间中分配内存给线程栈使用.新线程与创建它的线程在相同的进程上下文中运行.因此,新线程可以访问进程内核对象的所有句柄.进程中的所有内存以及同一个进程中其他所有线程的 ...

最新文章

  1. SQL Server 2005高可用性之复制(http://tech.it168.com/db/s/2007-05-15/200705150909375.shtml)
  2. 修改anaconda中conda和pip的源为清华源
  3. 让你不再害怕指针-摘自:无名
  4. 分析java中文乱码的原因
  5. @staticmethod和@classmethod的作用与区别
  6. idea存在包但是运行项目一直报java.lang.NoClassDefFoundError的问题
  7. 【JAVA SE】第三章 运算符、条件语句、switch结构、while循环、do…while循环、for循环、break关键字以及break和continue关键字
  8. DPDK 网卡收包流程
  9. bz2解压命令_Linux文件操作之文件压缩与解压缩命令详解
  10. jquery对url中的中文解码
  11. 苹果手机远程服务器桌面,如何用手机APP远程桌面管理Windows云服务器或电脑
  12. Python数据分析与机器学习-Python库分析科比生涯数据
  13. 费马小定理和欧拉定理
  14. Google网盘 百度网盘文件互传-Multcloud
  15. 量子计算机的基本构成,量子计算机的硬件单元 文/李联宁 1. 量子寄存器 存储一系列量子比特的体系称为量子寄存器。假设有一个由3比特构成的寄存器,在经典计算机中,可... - 雪球...
  16. 传统零售和新零售的本质区别
  17. 警惕,新增1本,被剔除1本,最新12月SCIE SSCI期刊目录更新
  18. 内核中的互斥锁的使用
  19. 硬盘开启NCQ功能全解
  20. 蚂蚁金服ATEC技术峰会:共探技术开放新生态

热门文章

  1. matlab h(z)变换成h(t),用Matlab进行系统函数H(s)仿真.ppt
  2. CAS机制实现原理分析
  3. 突发!Soul上市中止,因不正当竞争行为成被告,遭索赔410万美元
  4. 独立站Shopify如何通过TikTok引流?
  5. 洛谷P1765 手机
  6. 小程序基础-获取当前日期
  7. 联想Y470开机太卡,太慢解决方法
  8. 两种方法轻松将pdf转换成jpg格式
  9. matlab画星号图线,matlab,多条曲线画到一张图上
  10. MySQL常用增删改查操作(CRUD)