libco源代码分析(01) -- Closure源代码分析

前言

libco是腾讯微信开源的C/C++实现的协程库,在微信后台有大规模应用。

在早期微信后台业务逻辑实现中,大量采用了多进程或多线程同步模型。随着业务量不断增大,同步模型的弊端日益显现,在这种场景下,业务系统数据处理能力及整理吞吐量往往非常低。

为了解决此类问题,后台业务系统必须进行大规模改造,改造的方式有两种:

  1.  线程异步化改造;
  2.  协程异步化改造;

前一种方式往往要求将现有系统中所有同步模型全部替换为异步模型,无异于将整个系统从框架层开始全部重写,风险显然比较高。而后一种方式,由于hook了socket API,因此将对老系统代码的侵入性降到了最低。

libco的项目背景及整体设计思想,可以参考《C/C++协程库libco:微信怎样漂亮地完成异步化改造》一文。

闭包源代码分析

libco中提供了一份简单的闭包实现,接下去会分段进行分析。

代码片段一:

#ifndef __CO_CLOSURE_H__
#define __CO_CLOSURE_H__
struct stCoClosure_t 
{
public:
	virtual void exec() = 0;
};

这段代码本质上定义了Closure的基类,闭包在调用时,最终会调用exec()函数。

代码片段二:

//1.base 
//-- 1.1 comac_argc

#define comac_get_args_cnt( ... ) comac_arg_n( __VA_ARGS__ )
#define comac_arg_n( _0,_1,_2,_3,_4,_5,_6,_7,N,...) N
#define comac_args_seqs() 7,6,5,4,3,2,1,0
#define comac_join_1( x,y ) x##y

#define comac_argc( ... ) comac_get_args_cnt( 0,##__VA_ARGS__,comac_args_seqs() )
#define comac_join( x,y) comac_join_1( x,y )

上面定义的6个宏主要分为以下两类:

  1. comac_argc宏主要用于求出可变宏参数的个数。 注意:在这份实现中,最多支持7个宏参数求长度。
  2. comc_join宏主要用于将两个参数拼接为一个参数。

comac_argc宏展开举例:

comac_argc( A, B ) -> comac_get_args_cnt( 0, A, B, 7,6,5,4,3,2,1,0  ) -> comac_arg_n( 0, A, B, 7,6,5,4,3,2,1,0 ) -> 2

__VA_ARGS__代表宏参数是可变的,此处为什么需要添加前缀##呢?

补充说明:

为什么需要在__VA_ARGS__前添加##?

在gcc中,前缀##有一个特殊约定,即当##arg前面是逗号(,)时,如果arg为空,则##之前的逗号(,)将会被自动省去。

因此,当comac_argc()不填写任何参数时,宏将会被按照以下方式展开:

comac_argc( ) -> comac_get_args_cnt( 0, 7,6,5,4,3,2,1,0  ) -> comac_arg_n( 0, 7,6,5,4,3,2,1,0 ) -> 0

但是,对于C++11(-std=c++11),如果##arg中的arg为空,则##arg将会被默认转换为空字符串(""),此时,宏将会按照下面的方式展开:

comac_argc( ) -> comac_get_args_cnt( 0, "", 7,6,5,4,3,2,1,0  ) -> comac_arg_n( 0, "",  7,6,5,4,3,2,1,0 ) -> 1

代码片段三:

//-- 1.2 repeat
#define repeat_0( fun,a,... ) 
#define repeat_1( fun,a,... ) fun( 1,a,__VA_ARGS__ ) repeat_0( fun,__VA_ARGS__ )
#define repeat_2( fun,a,... ) fun( 2,a,__VA_ARGS__ ) repeat_1( fun,__VA_ARGS__ )
#define repeat_3( fun,a,... ) fun( 3,a,__VA_ARGS__ ) repeat_2( fun,__VA_ARGS__ )
#define repeat_4( fun,a,... ) fun( 4,a,__VA_ARGS__ ) repeat_3( fun,__VA_ARGS__ )
#define repeat_5( fun,a,... ) fun( 5,a,__VA_ARGS__ ) repeat_4( fun,__VA_ARGS__ )
#define repeat_6( fun,a,... ) fun( 6,a,__VA_ARGS__ ) repeat_5( fun,__VA_ARGS__ )


#define repeat( n,fun,... ) comac_join( repeat_,n )( fun,__VA_ARGS__)

上面这些宏主要用于定义重复操作。在后文中有语句举例。

代码片段四:

//2.implement
#if __cplusplus <= 199711L
#define decl_typeof( i,a,... ) typedef typeof( a ) typeof_##a;
#else
#define decl_typeof( i,a,... ) typedef decltype( a ) typeof_##a;
#endif
#define impl_typeof( i,a,... ) typeof_##a & a;
#define impl_typeof_cpy( i,a,... ) typeof_##a a;
#define con_param_typeof( i,a,... ) typeof_##a & a##r,
#define param_init_typeof( i,a,... ) a(a##r),

1. decl_typeof:主要用于获取变量a的类型。例如:

int a = 100;
decl_typeof( 1,a); 
==>
int a = 100;
typedef typeof(a) typeof_a;

2. impl_typeof:主要用于创建一个和变量a的类型相同的引用

3. impl_typeof_copy:主要用于创建一个和变量a类型相同的变量

4. con_param_typeof:用于生成类构造函数入参。

5. param_init_typeof:用于生成类构造函数初始化列表。

代码片段五:

//2.1 reference

#define co_ref( name,... )\
repeat( comac_argc(__VA_ARGS__) ,decl_typeof,__VA_ARGS__ )\
class type_##name\
{\
public:\
	repeat( comac_argc(__VA_ARGS__) ,impl_typeof,__VA_ARGS__ )\
	int _member_cnt;\
	type_##name( \
		repeat( comac_argc(__VA_ARGS__),con_param_typeof,__VA_ARGS__ ) ... ): \
		repeat( comac_argc(__VA_ARGS__),param_init_typeof,__VA_ARGS__ ) _member_cnt(comac_argc(__VA_ARGS__)) \
	{}\
} name( __VA_ARGS__ ) ;

上面这段宏定义,主要用于产生协程入参。例如,有以下一段代码:

int a = 100;
co_ref(ref,a);

经过宏展开后,代码如下:

int a = 100;

typedef typeof(a) typeof_a;
class type_ref
{
public:
	typeof_a & a;
	int _member_cnt;

	type_ref(typeof_a & ar, ...)
		: a(ar), _member_cnt(1)
	{
	}
}  ref(a);

本质上,就是构造了一个type_ref类,持有了对栈上变量a的引用。

_member_cnt(1)中,成员个数"1"实际上是由宏comac_argc自动推导出来的。

代码片段六:

//2.2 function

#define co_func(name,...)\
repeat( comac_argc(__VA_ARGS__) ,decl_typeof,__VA_ARGS__ )\
class name:public stCoClosure_t\
{\
public:\
	repeat( comac_argc(__VA_ARGS__) ,impl_typeof_cpy,__VA_ARGS__ )\
	int _member_cnt;\
public:\
	name( repeat( comac_argc(__VA_ARGS__),con_param_typeof,__VA_ARGS__ ) ... ): \
		repeat( comac_argc(__VA_ARGS__),param_init_typeof,__VA_ARGS__ ) _member_cnt(comac_argc(__VA_ARGS__))\
	{}\
	void exec()

#define co_func_end }

上述宏创建一个协程,代码举例如下:

#include "co_closure.h"
#include <stdio.h>

int main()
{
    int a = 100;	
    co_ref(ref, a);

    co_func(f, ref)
    {
        printf("hello, world!\n");
    }
    co_func_end;
}

宏展开之后,代码生成如下。可以看到,co_func定义的协程,引用了co_ref定义的参数。

int main()
{
	int a = 100;

	typedef typeof(a) typeof_a; 
	class type_ref 
	{
	public: 
		typeof_a & a; 
		int _member_cnt; 
		type_ref(typeof_a & ar, ...) : a(ar), _member_cnt(1) 
		{
		} 
	} ref(a);;

	typedef typeof(ref) typeof_ref; 
	class f : public stCoClosure_t 
	{
	public: 
		typeof_ref ref; 
		int _member_cnt; 
	public: 
		f(typeof_ref & refr, ...) : ref(refr), _member_cnt(1) 
		{
		} 
		void exec()
		{
			printf("hello, world!\n");
		}
	};
}
co_func经过宏展开后,生成了一个名称为f的类。只要创建这个类的实例,然后调用exec()方法,即可运行协程。


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 LR(0) 分析程序的设计与实现代码,用 Python 语言实现: ```python # LR(0) 分析程序 # 标识符常量 SHIFT = 1 REDUCE = 2 ACCEPT = 3 ERROR = 4 # 产生式类 class Production: def __init__(self, head, body): self.head = head self.body = body # 项目类 class Item: def __init__(self, production, dot): self.production = production self.dot = dot def __eq__(self, other): return self.production == other.production and self.dot == other.dot def __hash__(self): return hash(str(self.production) + str(self.dot)) # LR(0) 分析表类 class LR0Table: def __init__(self, grammar): self.grammar = grammar self.actions = {} self.gotos = {} # 构造项目集规范族 self.canonical_collection = self.build_canonical_collection() # 构造 LR(0) 分析表 self.build_table() # 构造项目集规范族 def build_canonical_collection(self): # 第一步:初始化 start_production = self.grammar.productions[0] start_item = Item(start_production, 0) closure = self.closure(set([start_item])) current_state = frozenset(closure) canonical_collection = {current_state: closure} # 第二步:循环直到项目集规范族没有变化 while True: for item in current_state: # 对于每个项目 A -> α·Bβ,进行 GOTO 操作 if not item.dot == len(item.production.body): symbol = item.production.body[item.dot] goto = self.goto(current_state, symbol) if not goto in canonical_collection: closure = self.closure(goto) canonical_collection[goto] = closure # 如果项目集规范族没有变化,则退出循环 if len(canonical_collection) == len(current_state): break else: current_state = list(canonical_collection.keys())[-1] return canonical_collection # 求闭包 def closure(self, items): closure = set(items) while True: new_items = set() for item in closure: # 对于每个项目 A -> α·Bβ,将 B -> γ 加入 new_items if not item.dot == len(item.production.body): symbol = item.production.body[item.dot] if symbol in self.grammar.non_terminals: for production in self.grammar.productions: if production.head == symbol: new_item = Item(production, 0) if not new_item in closure: new_items.add(new_item) if not new_items: break closure |= new_items return closure # 求 GOTO(A -> α·Bβ, b) def goto(self, items, symbol): goto = set() for item in items: if not item.dot == len(item.production.body) and item.production.body[item.dot] == symbol: goto.add(Item(item.production, item.dot + 1)) return frozenset(self.closure(goto)) # 构造 LR(0) 分析表 def build_table(self): for i, state in enumerate(self.canonical_collection): # 对于每个项目 A -> α·,将 ACTION[s, a] 设为 SHIFT(t),其中 t = GOTO[s, a] for item in state: if item.dot == len(item.production.body): if item.production.head == self.grammar.start_symbol: self.actions[(i, '$')] = (ACCEPT, None) else: for symbol in self.grammar.follow(item.production.head): self.actions[(i, symbol)] = (REDUCE, item.production) else: symbol = item.production.body[item.dot] goto = self.goto(state, symbol) if symbol in self.grammar.terminals: self.actions[(i, symbol)] = (SHIFT, goto) else: self.gotos[(i, symbol)] = goto # 执行 LR(0) 分析 def parse(self, input): stack = [0] output = [] while True: state = stack[-1] symbol = input[0] if (state, symbol) in self.actions: action, arg = self.actions[(state, symbol)] if action == SHIFT: stack.append(arg) input = input[1:] elif action == REDUCE: head = arg.head body = arg.body output.append(arg) for i in range(len(body)): stack.pop() state = stack[-1] stack.append(self.gotos[(state, head)]) elif action == ACCEPT: output.append(arg) return output else: raise Exception('Syntax error') else: raise Exception('Syntax error') ``` 此代码实现了 LR(0) 分析程序的主要功能,包括构造项目集规范族、构造 LR(0) 分析表和执行 LR(0) 分析。使用时需要提供一个文法对象(包括产生式和起始符号)和一个输入串。输出为分析树或语法错误。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值