Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
2024-RSOC
学习过程总结
新手学习
【2024-RSOC】夏令营Day3日记 : IPC机制
发布于 2024-07-24 23:30:17 浏览:631
订阅该版
[tocm] # **【2024-RSOC】Day3 : IPC机制** **【2024-RSOC】** 基于RT-Thread官方开发板星火一号,本篇参考RT-Thread入门pdf资料《RT-Thread 内核-线程间同步》,和夏令营老师讲解,编写而成。本内容面向小白,因为写这个的作者也是小白,跟着夏令营刚开始学,欸嘿(笑)。 ![0.png](https://oss-club.rt-thread.org/uploads/20240724/f54250dee4f4760af66a43dbc51e0813.png.webp) ![1.png](https://oss-club.rt-thread.org/uploads/20240724/92a06a6b42ebe42c36b759d7a08b1017.png.webp) [在线文档♥点♥我♥看♥](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/ipc1/ipc1) 如果初次使用spark的bsp软件包,未构建vscode文件,则参考我昨日发布[【2024-RSOC】夏令营Day2:初识rt-thread及多线程简单试用](https://club.rt-thread.org/ask/article/9da7f2983ce3264f.html)中的`初次搞机(干通官方bsp源码)`小节,确保工程文件能正常打开烧录例程,再往下进行。 ## 今日の夏令营の课前小玩法简介 ☆*:d(≧▽≦)b:*☆ ### **1. msh添加命令** 看好了,msh是这么用的!!!(p≧▽≦)p `MSH_CMD_EXPORT("对应函数名", "对应介绍");` 比如我们在main函数中添加一段代码,比如: ``` int hatsune_miku(void) { //我是函数 } MSH_CMD_EXPORT(hatsune_miku, HATSUNE MIKU); ``` 然后我们保存,`scons -j32`编译爽一下(p≧▽≦)p >scons小知识:因为我的139hx有32个县城,所以我是-j32,多核,爽 这时候打开端口,按TAB列出菜单,可以看见我们的MIKU出现了(●'◡'●) ![2.png](https://oss-club.rt-thread.org/uploads/20240724/1ad431662d21ba2b53643d7d3730a9be.png) [小节相关在线文档♥点♥我♥看♥](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/finsh/finsh?id=%e8%87%aa%e5%ae%9a%e4%b9%89-finsh-%e5%91%bd%e4%bb%a4) --- ### **2. menuconfig.exe配置** >**学妹小贴士 o(*////▽////*)q :** 如果你害怕初学乱配置给这个包搞坏,不用悲伤,不用着急,你复制一份出来,目录还是在bsp/stm32/下,但名字记得改下分清楚,比如这样: ![图片alt]![3.png](https://oss-club.rt-thread.org/uploads/20240724/8167b5cf433fe073a181a20996549604.png) 由于本次实验要用到官方写的软件包去学习,软件包官方提供了FAL组件供我们配置下载,具体介绍看这里[FAL相关在线文档♥点♥我♥看♥](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/fal/fal?id=_1%e3%80%81fal%e4%bb%8b%e7%bb%8d) 我们需要在软件包中找到今天IPC课程学到的例程,勾选并开启。 进入spark的板级支持包目录内,打开env窗口,输入`menuconfig.exe`,进入配置页面。 ![4.png](https://oss-club.rt-thread.org/uploads/20240724/72597ae9dbb29631c78f7be03a601228.png) AMI的BIOS苦了我多年,今日一见此界面,跟找到家似的亲切。 ![5.png](https://oss-club.rt-thread.org/uploads/20240724/b6f65e14b191b2a18f6a4c7ee217b3d6.png) 移动键盘上下键,向下找到`RT-Thread online packages`选项,按回车进入子菜单。向下继续找,找到`miscellaneous packages`,回车进入。进入后找到`samples: kernel and components samples`,再进入找到 `a kernel_samples package for rt-thread`,按照图示勾选。 ![6.png](https://oss-club.rt-thread.org/uploads/20240724/b31e9270530615a298b73f5dfbe0d91e.png) 一路esc,退出窗口时按照提示按Y保存退出即可。在env窗口中输入`pkgs --update`来拉取刚刚menuconfig选中的软件包。 ![7.png](https://oss-club.rt-thread.org/uploads/20240724/41c6cb2fb60536641030e9c611c7b583.png) 这时在spark的根目录下的packages中会出现我们拉取的软件包。 >**学妹小贴士 (●'◡'●) :**本篇作者不是学妹ಥ_ಥ --- ## 信号量,互斥量,事件集 刚刚成功拉取了软件包是不是爽了一把? ### 信号量 概念请自行阅读在线文档或者pdf[信号量在线文档♥点♥我♥看♥](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/ipc1/ipc1?id=%e4%bf%a1%e5%8f%b7%e9%87%8f) 文档看完了,那我们总结下信号量的基本操作语句: ![8.png](https://oss-club.rt-thread.org/uploads/20240724/4ab5dfeb26edd4e0ef3b8078234d4833.png.webp) ``` //创建函数如下: rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag); //删除函数如下: rt_err_t rt_sem_delete(rt_sem_t sem); //初始化函数如下: rt_err_t rt_sem_init(rt_sem_t sem, const char *name, rt_uint32_t value, rt_uint8_t flag) //脱离函数如下: rt_err_t rt_sem_detach(rt_sem_t sem); //获取信号量函数如下: rt_err_t rt_sem_take (rt_sem_t sem, rt_int32_t time); //无等待获取信号量函数如下: rt_err_t rt_sem_trytake(rt_sem_t sem); //释放信号量函数如下: rt_err_t rt_sem_release(rt_sem_t sem); ``` >上面七句话,混个脸熟,认脸就行。注意,这不是数学公式,不用死记硬背。 我们拉取的代码就是[信号量的使用例程文档](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/ipc1/ipc1?id=%e4%bf%a1%e5%8f%b7%e9%87%8f%e5%ba%94%e7%94%a8%e7%a4%ba%e4%be%8b)中的代码,查看代码可知,线程一的优先级比线程二高,在线程一释放信号量后线程二才能收到。 将板子连上电脑,spark根目录内打开env命令窗口,按下TAB,呼出命令列表,输入`semaphore_sample`,运行如下: ![9.png](https://oss-club.rt-thread.org/uploads/20240724/be7c5029358870543fd76795c7016d1d.png.webp) ### 互斥量 概念请自行阅读在线文档或者pdf[互斥量在线文档♥点♥我♥看♥](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/ipc1/ipc1?id=%e4%ba%92%e6%96%a5%e9%87%8f) 文档看完了,那我们总结下互斥量的基本操作语句: ![10.png](https://oss-club.rt-thread.org/uploads/20240724/55d99b780eaa64d8b5e5ecce889d2087.png) ``` //创建一个互斥量 rt_mutex_t rt_mutex_create (const char* name, rt_uint8_t flag); //删除互斥量 rt_err_t rt_mutex_delete (rt_mutex_t mutex); //初始化互斥量 rt_err_t rt_mutex_init (rt_mutex_t mutex, const char* name, rt_uint8_t flag); //脱离互斥量 rt_err_t rt_mutex_detach (rt_mutex_t mutex); //获取互斥量 rt_err_t rt_mutex_take (rt_mutex_t mutex, rt_int32_t time); //无等待获取互斥量 rt_err_t rt_mutex_trytake(rt_mutex_t mutex); //释放互斥量 rt_err_t rt_mutex_release(rt_mutex_t mutex); ``` >上面七句话,混个脸熟,认脸就行。注意,这不是数学公式,不用死记硬背。 在env中,键入`mutex_sample`,运行[互斥量的应用示例](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/ipc1/ipc1?id=%e4%ba%92%e6%96%a5%e9%87%8f%e5%ba%94%e7%94%a8%e7%a4%ba%e4%be%8b),结果如图。 ![11.png](https://oss-club.rt-thread.org/uploads/20240724/33b7a25bd79d2f638b19d8412d163f13.png.webp) ### 事件集 概念请自行阅读在线文档或者pdf[事件集在线文档♥点♥我♥看♥](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/ipc1/ipc1?id=%e4%ba%8b%e4%bb%b6%e9%9b%86) 文档看完了,那我们总结下互斥量的基本操作语句: ![12.png](https://oss-club.rt-thread.org/uploads/20240724/37407cc5e897c56359c0c2df10a735f8.png) ``` //创建事件集 rt_event_t rt_event_create(const char* name, rt_uint8_t flag); //删除事件集 rt_err_t rt_event_delete(rt_event_t event); //初始化事件集 rt_err_t rt_event_init(rt_event_t event, const char* name, rt_uint8_t flag); //脱离事件集 rt_err_t rt_event_detach(rt_event_t event); //发送事件 rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set); //接收事件 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); ``` >上面六句话,混个脸熟,认脸就行。注意,这不是数学公式,不用死记硬背。欸?怎么少一句? 在env中,键入`event_sample`,运行[事件集的应用示例](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/ipc1/ipc1?id=%e4%ba%8b%e4%bb%b6%e9%9b%86%e5%ba%94%e7%94%a8%e7%a4%ba%e4%be%8b),结果如图。 ![13.png](https://oss-club.rt-thread.org/uploads/20240724/aca37df15965a8992856a3cb1bdf64d5.png) ## 邮箱,消息队列, ### 邮箱 概念请自行阅读在线文档或者pdf[邮箱在线文档♥点♥我♥看♥](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/ipc2/ipc2?id=%e9%82%ae%e7%ae%b1) 文档看完了,那我们总结下邮箱的基本操作语句: ![14.png](https://oss-club.rt-thread.org/uploads/20240724/46140f1668d2c79be8864b50077a8540.png) ``` //动态创建一个邮箱 rt_mailbox_t rt_mb_create (const char* name, rt_size_t size, rt_uint8_t flag); //删除邮箱 rt_err_t rt_mb_delete (rt_mailbox_t mb); //初始化邮箱 rt_err_t rt_mb_init(rt_mailbox_t mb, const char* name, void* msgpool, rt_size_t size, rt_uint8_t flag) //脱离邮箱 rt_err_t rt_mb_detach(rt_mailbox_t mb); //发送邮件 rt_err_t rt_mb_send (rt_mailbox_t mb, rt_uint32_t value); //等待方式发送邮件 rt_err_t rt_mb_send_wait (rt_mailbox_t mb, rt_uint32_t value, rt_int32_t timeout); //发送紧急邮件 rt_err_t rt_mb_urgent (rt_mailbox_t mb, rt_ubase_t value); //接收邮件 rt_err_t rt_mb_recv (rt_mailbox_t mb, rt_uint32_t* value, rt_int32_t timeout); ``` >上面八句......欸怎么是八句? 在env中,键入`mailbox_sample`,运行[邮箱的应用示例](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/ipc2/ipc2?id=%e9%82%ae%e7%ae%b1%e4%bd%bf%e7%94%a8%e7%a4%ba%e4%be%8b),结果如图。 ![15.png](https://oss-club.rt-thread.org/uploads/20240724/648ab407b155a316b235febf9c88d50f.png) ### 消息队列 概念请自行阅读在线文档或者pdf[消息队列在线文档♥点♥我♥看♥](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/ipc2/ipc2?id=%e6%b6%88%e6%81%af%e9%98%9f%e5%88%97) 文档看完了,那我们总结下邮箱的基本操作语句: ![16.png](https://oss-club.rt-thread.org/uploads/20240724/b01f0b259c5d2fd7b3d8f9a579572588.png) ``` //创建消息队列 rt_mq_t rt_mq_create(const char* name, rt_size_t msg_size, rt_size_t max_msgs, rt_uint8_t flag); //删除消息队列 rt_err_t rt_mq_delete(rt_mq_t mq); //初始化消息队列 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); //脱离消息队列 rt_err_t rt_mq_detach(rt_mq_t mq); //发送消息 rt_err_t rt_mq_send (rt_mq_t mq, void* buffer, rt_size_t size); //等待方式发送消息 rt_err_t rt_mq_send_wait(rt_mq_t mq, const void *buffer, rt_size_t size, rt_int32_t timeout); //发送紧急消息 rt_err_t rt_mq_urgent(rt_mq_t mq, void* buffer, rt_size_t size); //接收消息 rt_ssize_t rt_mq_recv (rt_mq_t mq, void* buffer, rt_size_t size, rt_int32_t timeout); ``` >以上就是邮箱的八句......欸?哪里不对的样子? 在env中,键入`msgq_sample`,运行[消息队列的应用示例](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/ipc2/ipc2?id=%e6%b6%88%e6%81%af%e9%98%9f%e5%88%97%e5%ba%94%e7%94%a8%e7%a4%ba%e4%be%8b),结果如图。 ![17.png](https://oss-club.rt-thread.org/uploads/20240724/e4c328faf80af979bc4c8172424578c5.png) ## 今日作业:至少用两种IPC编写试验代码 参考我昨日发布[【2024-RSOC】夏令营Day2:初识rt-thread及多线程简单试用](https://club.rt-thread.org/ask/article/9da7f2983ce3264f.html)中的`小试牛刀(hello world)`小节,仿照新建c文件,确保文件能正常新建并编译。今天作业命名为Day3文件夹,文件目录如图示: ![18.png](https://oss-club.rt-thread.org/uploads/20240724/dd64853bf1af67f3407e6ba13110bbd8.png) ### 思路设计 板载旁边有一颗led灯珠,内部包含两个灯。 缝合两种机制,我们创建5个线程。 线程1在count每计数10次时,发送一个信号量,线程2在接收信号量后,对number进行加1操作,加到10后完成任务亮红灯并发送一次事件3。 线程3在count每计数10次时,发送一个信号量,线程4在接收信号量后,对number进行加1操作,加到10后完成任务亮蓝灯并发送一次事件5。 线程5在收到3和5后才能报告allover并退出。 代码如下: ``` #include
#include
#include
#ifndef RT_USING_NANO #include
#endif /* RT_USING_NANO */ #define GPIO_LED_B GET_PIN(F, 11) #define GPIO_LED_R GET_PIN(F, 12) /* 指向信号量的指针 */ static rt_sem_t dynamic_sem = RT_NULL; #define THREAD_PRIORITY 9 #define THREAD_TIMESLICE 5 #define EVENT_FLAG3 (1 << 3) #define EVENT_FLAG5 (1 << 5) /* 事件控制块 */ static struct rt_event event; #ifdef rt_align rt_align(RT_ALIGN_SIZE) #else ALIGN(RT_ALIGN_SIZE) #endif static char thread1_stack[1024]; static struct rt_thread thread1; /* 线程1入口函数 */ static void thread1_entry(void *param) { static rt_uint8_t count = 0; while (1) { if (count <= 100) { count++; } else return; /* count每计数10次,就释放一次信号量 */ if (0 == (count % 10)) { //rt_kprintf("thread1 release a dynamic semaphore.\n"); rt_sem_release(dynamic_sem); } } } #ifdef rt_align rt_align(RT_ALIGN_SIZE) #else ALIGN(RT_ALIGN_SIZE) #endif static char thread2_stack[1024]; static struct rt_thread thread2; /* 线程2入口 */ static void thread2_entry(void *param) { 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("thread2 take a dynamic semaphore, failed.\n"); rt_sem_delete(dynamic_sem); return; } else { number++; rt_kprintf("thread2 take a dynamic semaphore. number = %d\n", number); if (number==5) { rt_pin_write(GPIO_LED_R, PIN_LOW); rt_kprintf("thread1and2: over\n"); rt_event_send(&event, EVENT_FLAG3); rt_thread_mdelay(200);/* code */ return; } } } } #ifdef rt_align rt_align(RT_ALIGN_SIZE) #else ALIGN(RT_ALIGN_SIZE) #endif static char thread3_stack[1024]; static struct rt_thread thread3; /* 线程3入口 */ static void thread3_entry(void *param) { static rt_uint8_t count = 0; while (1) { if (count <= 100) { count++; } else return; /* count每计数10次,就释放一次信号量 */ if (0 == (count % 10)) { //rt_kprintf("thread3 release a dynamic semaphore.\n"); rt_sem_release(dynamic_sem); } } } #ifdef rt_align rt_align(RT_ALIGN_SIZE) #else ALIGN(RT_ALIGN_SIZE) #endif static char thread4_stack[1024]; static struct rt_thread thread4; /* 线程4入口 */ static void thread4_entry(void *param) { 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("thread4 take a dynamic semaphore, failed.\n"); rt_sem_delete(dynamic_sem); return; } else { number++; rt_kprintf("thread4 take a dynamic semaphore. number = %d\n", number); if (number==5) { rt_pin_write(GPIO_LED_B, PIN_LOW); rt_kprintf("thread3and4: over\n"); rt_event_send(&event, EVENT_FLAG5); rt_thread_mdelay(200);/* code */ return; } } } } #ifdef rt_align rt_align(RT_ALIGN_SIZE) #else ALIGN(RT_ALIGN_SIZE) #endif static char thread5_stack[1024]; static struct rt_thread thread5; /* 线程5入口 */ static void thread5_entry(void *param) { rt_uint32_t e; if (rt_event_recv(&event, (EVENT_FLAG3 | EVENT_FLAG5), RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &e) == RT_EOK) { rt_kprintf("allover\n" ); } } int hatsune_miku(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_err_t result; /* 初始化事件对象 */ result = rt_event_init(&event, "event", RT_IPC_FLAG_PRIO); if (result != RT_EOK) { rt_kprintf("init event failed.\n"); return -1; } //线程1 rt_thread_init(&thread1, "thread1", thread1_entry, RT_NULL, &thread1_stack[0], sizeof(thread1_stack), THREAD_PRIORITY , THREAD_TIMESLICE); #ifdef RT_USING_SMP /* 绑定线程到同一个核上,避免启用多核时的输出混乱 */ rt_thread_control(&thread1, RT_THREAD_CTRL_BIND_CPU, (void*)0); #endif rt_thread_startup(&thread1); //线程2 rt_thread_init(&thread2, "thread2", thread2_entry, RT_NULL, &thread2_stack[0], sizeof(thread2_stack), THREAD_PRIORITY - 1, THREAD_TIMESLICE); #ifdef RT_USING_SMP /* 绑定线程到同一个核上,避免启用多核时的输出混乱 */ rt_thread_control(&thread2, RT_THREAD_CTRL_BIND_CPU, (void*)0); #endif rt_thread_startup(&thread2); //线程3 rt_thread_init(&thread3, "thread3", thread3_entry, RT_NULL, &thread3_stack[0], sizeof(thread3_stack), THREAD_PRIORITY -2, THREAD_TIMESLICE); #ifdef RT_USING_SMP /* 绑定线程到同一个核上,避免启用多核时的输出混乱 */ rt_thread_control(&thread3, RT_THREAD_CTRL_BIND_CPU, (void*)0); #endif rt_thread_startup(&thread3); //线程4 rt_thread_init(&thread4, "thread4", thread4_entry, RT_NULL, &thread4_stack[0], sizeof(thread4_stack), THREAD_PRIORITY - 3, THREAD_TIMESLICE); #ifdef RT_USING_SMP /* 绑定线程到同一个核上,避免启用多核时的输出混乱 */ rt_thread_control(&thread4, RT_THREAD_CTRL_BIND_CPU, (void*)0); #endif rt_thread_startup(&thread4); //线程5 rt_thread_init(&thread5, "thread5", thread5_entry, RT_NULL, &thread5_stack[0], sizeof(thread5_stack), THREAD_PRIORITY - 4, THREAD_TIMESLICE); #ifdef RT_USING_SMP /* 绑定线程到同一个核上,避免启用多核时的输出混乱 */ rt_thread_control(&thread4, RT_THREAD_CTRL_BIND_CPU, (void*)0); #endif rt_thread_startup(&thread5); return 0; } /* 导出到 msh 命令列表中 */ MSH_CMD_EXPORT(hatsune_miku, hatsune miku); ``` 运行结果如下: ![19.png](https://oss-club.rt-thread.org/uploads/20240724/0b98c08e3488de0130197a5846eb504c.png) 板子上两个灯同时亮起(┬┬﹏┬┬)。
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
河南理工大学恁带劲儿
俺是计算机协会硬件部嘞
文章
5
回答
0
被采纳
0
关注TA
发私信
相关文章
1
大神们,rt-thread启用WDT了,但是还是没启动,怎么办?
2
求一个师傅带带队,有偿交学费 肯吃苦
3
自己按照官方手册 在drv_gpio.c里面找不到PIN脚信息
4
rtt studio f4默认生成的代码无法使用
5
官方例程中的 USB设置配置不成功
6
STM32F4的虚拟串口 的USB时钟如何配置
7
AT24CXX 软件包函数 at24cxx的问题
8
rtthread studio和bsp文件之间生成的区别和联系?
9
pwm根据手册修改为对应的引脚后无效
10
文件系统挂实验 ls命令异常
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
ota在线升级
UART
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
张世争
8
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
KunYi
6
个答案
1
次被采纳
本月文章贡献
程序员阿伟
6
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部