c语言架构的一点构想
核心思想:
1.数据结构,抽象数据模型,struct里面有消息队列,有type,有id,有callback函数指针,有封装好的op->set,op->get等函数指针,将callback的函数指针和参数指针都封装好。
2.使用事件驱动的逻辑框架。一个事件触发一个阻塞的任务队列去执行。
3.常见的数据结构,包括红黑树,list,queue,堆,栈等等。
4.多线程应用减少互斥的逻辑,如果必须有互斥的话,禁止嵌套互相调用出现锁死。
5.如果资源紧张,并且事件的消息不是特别多,则使用一个线程监听多个类型的事件来串行的处理并发的任务,当然可以根据任务的优先级,选择监听的顺序,并减少每个任务的处理时间,防止阻塞其他任务的执行。
典型case:
1.在资源不受限的linux平台上。
创建多个任务,每个任务监听一个队列,使用sem_wait的方式阻塞,当有队列中的新数据的时候,可以sem_signal触发这个线程去执行,需要和其他线程通信时,向其他线程发送那个线程需要的事件就可以了。如果是紧急事件需要处理,则直接访问待执行队列的成员变量,防止任务很紧急,但是队列中还有很多其他的消息没有取出来这种场景。
阻塞函数需要改为非阻塞的时候,启动一个后台执行的任务,交给work_q去处理。
非阻塞函数实现为阻塞函数时,首先是是否有这个必要?其实可以类似android系统一样,我调用init,然后再监听init done的广播来确定是否初始化成功,异步实现也可以。但是如果真的需要同步知道某个任务的执行结果,比如说除了等之外,其他的逻辑没有任何可以执行的,那么可以使用sem_wait的方式实现一个timeout的等待,然后传递sem_wait的信号量句柄给到后台执行任务的callback函数中。
订阅和发布,可以参考开源代码,注意的一点是,发布者不需要获取订阅者是否收到了广播,这样子就失去了意义了,就像android系统的广播一样。
有timeout执行时间的限制的话,可以在时间到到达之后,仍然没有回复的话,返回一个默认的错误ack,同时在后面如果收到了timeout的事件回复,直接忽略。可以设置是否需要恢复,是同步的,还是异步的。
状态机:可以按照hairos的写法,就是有点炫技。
2.在资源受限的linux平台上。
参考wpa_supplicant,是在一个线程里面处理wifi的整个协议栈,但是我推测,wifi虽然数据包很多,但是在数据建立通道后,控制消息是很少的,所以大部分时间可以用来处理数据的事件,如果数据和控制消息都很多,并且要求实时性,我估计它也是搞不定的。猜测是使用了epoll+event_fd和timer_id来进行了封装。
3.在资源受限的rtos平台上。
参考zephyr,一个线程监听多个任务队列,监听的实现需要自己去封装。
4.在资源受限的裸跑程序中。
需要有保护进程上线文的硬件支持,不然没有办法实现。
或者启动一个timer,周期的去执行不同的函数逻辑,但是有一个问题是,如果其中一个函数出现了阻塞,则其他函数没有执行的条件了。
5.参考开源框架:
libevent:
libev:
libuv:
libhv:
协程:
zephyr:
wpa_supplicant:
6.
新接口,未经过大量使用验证的,用experimental来进行标注。
旧接口,已废弃的接口,可能会出现兼容性的问题,用experimental来进行标注。
7.函数名字可以定义为和功能,组件名字相关,但是结构体的定义,函数指针的定义,尽量和功能有关,不要和组件有关,和组件用关系的话,在对组件进行封装时,会出现很繁琐的问题,需要定义多个一样的结构体。