跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 开发利器——C 语言必备实用第三方库
未分類
9 2 月 2021

开发利器——C 语言必备实用第三方库

开发利器——C 语言必备实用第三方库

資深大佬 : monkeyNik 3

本文转载自本人头条号: https://www.toutiao.com/i6926789516594479624/

转载请注明出处,感谢!

对于广大 C 语言开发者来说,缺乏类似 C++ STL 和 Boost 的库会让开发受制于基础库的匮乏,也因此导致了开发效率的骤降。这也使得例如 libevent 这类事件库(基础组件库)一时间大红大紫。

今天,笔者给大家带来一款基础库,这套库不仅仅提供了常用的数据结构、算法,如红黑树、斐波那契堆、队列、KMP 算法、RSA 算法、各类哈希算法、数据恢复算法等等,还提供了多进程框架、多线程框架、跨平台高性能事件等实用内容。注意:这是一款不依赖第三方的库。

除此以外,它也是笔者之前文章(Melang 脚本语言)中的核心库。这也就意味着,使用该库,不仅可以快速获得上述内容,还可以让开发者所构建的系统很方便地引入脚本语言的功能。

它就是——Melon

开发利器——C 语言必备实用第三方库

Github: https://github.com/Water-Melon/Melon 。

下面,笔者便带诸位一览这个库的功能。

数据结构

Melon 中包含如下数据结构的实现:

  • 双向链表
  • 斐波那契堆
  • 哈希表
  • 队列
  • 红黑树
  • 栈

其中:

  • 双向链表使用宏实现,可以通过两行宏函数即可完成双向队列插入和删除操作的声明和定义。
  • 斐波那契堆是一个最小堆,在库中的事件功能中用于实现定时器的维护管理,当然,也可以单独使用。

以上结构几乎均可在其对应名称的头文件中找到数据结构定义以及函数定义。

一般情况下,数据结构的使用都是函数调用形式,因此也尽可能降低了不同组件间的耦合度。

算法

Melon 中包含的算法如下:

  • 加密算法:AES 、DES 、3DES 、RC4 、RSA
  • 哈希算法:MD5 、SHA1 、SHA256
  • Base64
  • 大数计算
  • FEC
  • JSON
  • 矩阵运算
  • 里德所罗门编码
  • 正则匹配算法
  • KMP

如上算法基本都在其各自头文件中可以找到对应的函数声明以及必要的数据结构定义。

其中,FEC 与里德所罗门编码均属于纠错码,FEC 常用于 RTP 中做数据修复,而里德所罗门编码既可以用于实时语音中丢包恢复,也可以用于冗余阵列( RAID )和其他 UDP 丢包恢复的场景。关于里德所罗门编码,感兴趣的读者可以阅读笔者之前的文章:神奇的数据恢复算法。

其他组件

前面的都是常规操作,这里才是重头戏。

Melon 中还包括如下实用组件:

  • 内存池
  • 数据链
  • TCP 封装
  • 事件机制
  • 文件缓存
  • HTTP 处理
  • 脚本语言
  • 词法分析器
  • websocket
  • 多进程框架
  • 多线程框架

因 Melon 作者 Nginx 中毒较深,所以 Melon 中部分机制与 Nginx 较为相似。

内存池:这里内存池不仅支持对从堆中分配的内存进行管理,还支持对共享内存的管理。

数据链与 TCP 封装:TCP 封装中包含了阻塞与非阻塞下的收发逻辑,并利用数据链结构来存放发送数据与接收数据。

事件机制:事件机制中不仅支持 epoll 、select,还支持 Kqueue,库在编译前会自行检测平台支持情况。事件包含了:

  • 句柄(文件描述符)事件:读、写、出错事件,以及超时事件(主要用于超时断开链接);
  • 定时事件(与句柄超时是两码事);
  • 信号处理事件:这里的信号处理并非一个信号只能有一个处理事件,而是设置多少个处理函数就会执行多少个;

文件缓存:参考 Nginx 文件缓存,避免对同一文件的重复打开浪费文件描述符资源。

HTTP:包含了 HTTP 的接收解析和发送,该套接口依赖于数据链结构来进行处理,因此可配合TCP 封装一同使用。

脚本语言:内容较多,可另行参考:Melang 脚本语言。

词法分析器:之所以这个单独算一个功能组件,是因为在 Melon 中,配置文件解析就是使用该词法分析器处理的。仅通过三行 C 代码就可以实现一个最最基础的词法分析器,这也归功于 C 语言宏的强大。

websocket:该部分依赖于HTTP组件。

多进程:多进程采用一主多从模式,主进程做管理,从进程处理实际业务。主进程与从进程之间由 socketpair 相连,因此从进程异常退出,主进程会立刻拉起一个新的子进程,同时主子进程也可以通过该 socketpair 进行数据通信。除了自身子进程可以管理,也可以通过配置文件配置来拉起其他程序作为自己的子进程来管理,有些类似于 supervisord 。

多线程:多线程分为两类,一类是常规的线程池,另一类是模块化的线程。后者也是一主多从模型,主与子之间是通过 socketpair 进行通信,而每一个子线程都有其入口函数(类似 main 函数),每一个子线程通常都是处理一类单一事务。

使用举例

上面说了那么多,下面就来看一个多进程的例子。

首先,我们要先安装 Melon:

$ git clone https://github.com/Water-Melon/Melon.git $ ./configure $ make $ sudo make install $ sudo echo "/usr/local/melon/lib/" >> /etc/ld.so.conf $ sudo ldconfig 

安装好后,Melon 会被安装在 /usr/local/melon 下。

接着,我们创建一个名为 hello.c 的源文件来完成我们期望的功能:

#include <stdio.h> #include "mln_core.h" #include "mln_log.h" #include "mln_event.h"  char text[1024];  static int global_init(void); static void worker_process(mln_event_t *ev); static void print_handler(mln_event_t *ev, void *data);  int main(int argc, char *argv[]) {     struct mln_core_attr cattr;     cattr.argc = argc;     cattr.argv = argv;     cattr.global_init = global_init;     cattr.worker_process = worker_process;     return mln_core_init(&cattr); }  static int global_init(void) {     //global variable init function     int n = snprintf(text, sizeof(text)-1, "hello worldn");     text[n] = 0;     return 0; }  static void worker_process(mln_event_t *ev) {     //we can set event handler here     //let's set a timer     mln_event_set_timer(ev, 1000, text, print_handler); }  static void print_handler(mln_event_t *ev, void *data) {     mln_log(debug, "%sn", (char *)data);     mln_event_set_timer(ev, 1000, data, print_handler); } 

这段代码主要是初始化了一个全局变量,然后给每一个子进程创建了一个定时事件,即每一秒中输出一个 hello world 。

我们先进行编译链接生成可执行程序:

$ gcc -o hello hello.c -I /usr/local/melon/include/ -L /usr/local/melon/lib/ -lmelon 

然后,我们需要先修改 Melon 库的配置文件:

$ sudo vim /usr/local/melon/conf/melon.conf  log_level "none"; //user "root"; daemon off; core_file_size "unlimited"; //max_nofile 1024; worker_proc 1; thread_mode off; framework off; log_path "/usr/local/melon/logs/melon.log"; /*  * Configurations in the 'exec_proc' are the  * processes which are customized by user.  *  * Here is an example to show you how to  * spawn a program.  *     keepalive "/tmp/a.out" ["arg1" "arg2" ...]  * The command in this example is 'keepalive' that  * indicate master process to supervise this  * process. If process is killed, master process  * would restart this program.  * If you don't want master to restart it, you can  *     default "/tmp/a.out" ["arg1" "arg2" ...]  *  * But you should know that there is another  * arugment after the last argument you write here.  * That is the file descriptor which is used to  * communicate with master process.  */ exec_proc {    // keepalive "/tmp/a"; } thread_exec { //    restart "hello" "hello" "world"; //    default "haha"; } 

我们做如下修改:

  • framework off; –> framework on;
  • worker_proc 1; –> worker_proc 3;

这样,多进程框架将被启用,且会产生三个子进程。

程序启动后如下:

$ ./hello Start up worker process No.1 Start up worker process No.2 Start up worker process No.3 02/08/2021 09:34:46 GMT DEBUG: hello.c:print_handler:39: PID:25322 hello world  02/08/2021 09:34:46 GMT DEBUG: hello.c:print_handler:39: PID:25323 hello world  02/08/2021 09:34:46 GMT DEBUG: hello.c:print_handler:39: PID:25324 hello world  02/08/2021 09:34:47 GMT DEBUG: hello.c:print_handler:39: PID:25322 hello world  02/08/2021 09:34:47 GMT DEBUG: hello.c:print_handler:39: PID:25323 hello world  02/08/2021 09:34:47 GMT DEBUG: hello.c:print_handler:39: PID:25324 hello world  ... 

这时,可以 ps 看一下,一共存在四个 hello 进程,一个为主,其余三个为子进程。

小结

事实上,Melon 并不会有过多条条框框需要开发者小心谨慎怕踩坑。与 Skynet 类似,Melon 提供的绝大多数内容都可独立使用,而不必一定与多进程多线程框架结合。因此,这也给了使用者极大的自由度。

Melon 的官方 QQ 群号:756582294

感谢阅读,欢迎各位在评论区留言评论。

大佬有話說 (26)

  • 資深大佬 : hxndg

    不同内存模型下的顺序一致性怎么做的?

  • 主 資深大佬 : monkeyNik

    @hxndg 兄弟想多了

  • 資深大佬 : AndyAO

    虽然目前还用不到,但感觉好像是很不错的东西,为主的奉献精神点个赞 / 顶个帖儿.

  • 資深大佬 : hxndg

    @monkeyNik 没懂,堆内存和顺序一致性有啥关系?

  • 主 資深大佬 : monkeyNik

    @hxndg

  • 資深大佬 : mintist

    还有人记得 C,哈哈哈哈

  • 主 資深大佬 : monkeyNik

    @mintist 光复我大 C 哈哈哈~

  • 資深大佬 : gaigechunfeng

    必须支持,先 make 一下。
    现在已经基本脱离 C 语言了。

  • 資深大佬 : rim99

    赞,不过现在需要写 C/C++的项目越来越少

  • 資深大佬 : commoccoom

    插眼,刚刚开始学习 C 的路过

  • 資深大佬 : CismonX

    光从 3700 多行的纯文本文档就能看出来主很用心

  • 資深大佬 : jfcai

    先收藏,说不定哪天用得上

  • 主 資深大佬 : monkeyNik

    @CismonX 多谢兄台的建议,其实之前忙于内部脚本语言的文档和站点建设还有 bug 修复就没完善这部分,这部分确实需要完善一下,目前感觉看着比较乱

  • 資深大佬 : codehz

    1 说的应该是可见性问题吧,就是一个线程对共享变量的修改在别的线程角度的可见性,但是主这既然没有采用共享内存的设计,就应该不会有可见性的问题(

  • 資深大佬 : BingoXuan

    兼容 ANSI C 规范不?

  • 主 資深大佬 : monkeyNik

    @codehz 其实是支持共享内存的哦,内存池可以分配共享内存。多线程的话就使用 pthread 下的锁或者库内置的自旋锁都行,多进程处理共享内存的话,默认封装的是跨进程的 pthread 读写锁,不过分配与释放函数内不会默认调用加锁解锁,所以使用者可以在外部用其他锁来替代。

  • 主 資深大佬 : monkeyNik

    @BingoXuan 严格来说不兼容,里面是用到一些 gnu c 的东西,例如:inline,可变参宏,__attribute__,宏拼接之类的功能。
    不过目前这个库在 CentOS MacOS Freebsd 上都可以正常使用,并且 mac 上也支持 x86 和 arm 架构 cpu

  • 資深大佬 : silencht

    先给个星 mark 一下 O(∩_∩)O

  • 資深大佬 : byaiu

    atomic 也有 c 库自带的 如果支持新一点的 c11 可能就能直接用了

  • 主 資深大佬 : monkeyNik

    感谢各位的意见和建议,积累近 7 年的成果能够被大家支持,是这一年里我最大的收获,我也会继续维护和增加新功能,努力不负所望。
    新的一年里,祝大家牛

  • 主 資深大佬 : monkeyNik

    哎…手抖了…

  • 資深大佬 : wtdg86ok

    star 了,前辈真厉害~

  • 資深大佬 : codehz

    @monkeyNik 加锁也没问题,主要问题出在设计“无锁”结构上,容易踩坑,弄出只有 x86 系列能跑的设计(

  • 資深大佬 : geekzhu

    虽然不懂,但是感觉写这东西的都是大佬

  • 主 資深大佬 : monkeyNik

    新文已经发布啦: https://www.v2ex.com/t/753269
    关于 Melon 中多线程开发的内容,期待感兴趣的小伙伴来阅读

  • 主 資深大佬 : monkeyNik

    各位实在不好意思,之前 QQ 群设置有问题导致无法搜索到,感谢反馈,已经可以搜索到了。

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具