理解asio中strand的用法

05 Jan 2019 | C/CPP, asio |

设想一个常见的场景,我们设计一个服务器,每当到来一个新的请求时,我们需要读写一个全局的共享对象。在多线程环境下,多个线程同时操作一个共享的对象是不安全的。因此,我们需要对共享对象的操作进行同步。通用做法是用锁来保护,如果对其操作全部在asio的回调函数中进行,那么通常会用一个strand来使回调之间同步执行,方法是调用strand.wrap(handler)或者asio::bind_executor(strand, handler)。这也是strand的常见用法。

要记住的是strand只是保证回调之间的同步。另一种场景下我们需要异步操作 本身 不能被多个线程同时执行。以最常见的为asio::tcp::socket为例,根据文档,socket对象的线程安全类型是:

Thread Safety

Distinct objects: Safe.

Shared objects: Unsafe.

即多个线程共享同一个socket对象时不保证线程安全。不过大部分情况我们不需要考虑线程安全的问题,因为我们通常会这样来使用(以下是简写):

Continue Reading →

关于C函数能否抛出异常的讨论

05 Jan 2019 | C/CPP, 异常 |

C语言在语言层面上没有“异常”的概念,也不提类似C++那样能抛出异常的手段。但是,如果在C++中调用C的函数,不能就此完全忽略异常检查。特别是自从C++11开始,不能钦定一个C函数调用是noexcept。至于为什么,下面说几个蛋疼的案例。

案例1

我们知道,通过extern "C",C++编译器完全可以导出一个C函数接口,尽管函数内部可能包含C++的调用。如果这些C++代码会抛异常,那么最终的C接口运行时也会抛出异常。代码如下:

Continue Reading →

C++奇技淫巧之访问private变量

17 Aug 2018 | C/CPP, 奇技淫巧 |

众所周知,C++中private成员只能在类内部访问,就算是继承也无法直接访问到。想在其他类/函数中访问private成员,几乎只能通过友元(friend)实现。由于友元是侵入性的,当你引用了第三方类库,又不能对其修改时,就没法利用友元了。

然而,C++作为世界上拥有特性最多的语言,特别是指针、模板等怪兽级特性,成为了许多人拿来挑战其中条条框框的武器,private禁咒也被各种形式突破。下面盘点一下访问private成员的各种奇技淫巧。

Continue Reading →

记一次时间戳导致的编译失败

16 Aug 2018 | 编译, Bug |

背景

最近接手一个老项目,项目结构大体示意如下:

project
    ├── packaging
    │   ├── Makefile
    │   └── project.spec
    └── src
        ├── knot-2.3.1
        │   ├── aclocal.m4
        │   ├── ar-lib
        │   ├── compile
        │   ├── config.guess
        │   ├── config.sub
        │   ├── configure
        │   ├── configure.ac
        │   ├── depcomp
        │   ├── install-sh
        │   ├── libtap
        │   ├── ltmain.sh
        │   ├── m4
        │   ├── Makefile.am
        │   ├── Makefile.in
        │   └── missing
        └── Makefile

项目目录中包含了第三方的项目knot-2.3.1(knot是什么不重要,重要的是它用了autotools)。src目录下的Makefile中,调用了knot的编译流程:

src/Makefile:

knot:
	cd ${KNOT_DIR}/..; \
	./configure; \
	make

位于packaging下的Makefile是用来生成rpm安装包的,部分内容如下:

packaging/Makefile:

all: rpm

rpm: $(TARBALL)
	@mkdir -p {BUILD,BUILDROOT,SRPMS,SPECS}
	@rpmbuild --define "_topdir ${PWD}" --define "_sourcedir ${PWD}"  \
	--define "buildroot ${PWD}/BUILDROOT" --define "_rpmdir ${PWD}" -ba ${SPECFILE}

$(TARBALL):
	@rm -rf $(PKG_NAME)-$(PKG_VERSION)
	cd ${PROJ_ROOT}/.. && git archive --format=tar --prefix=/ $(TAG) src | gzip >packaging/${TARBALL}
	@rm -rf $(PKG_NAME)-$(PKG_VERSION)

由于项目是通过git进行版本控制,这里通过git对项目的src目录进行打包,然后运行rpmbuild编译成rpm包。

按道理说,在packaging目录下编译和在src目录下编译,出了是否打包成rpm之外,都是完全一样的。然而,实际操作后发现,在packaging下可以正常编译,而在src目录下运行make会报一个错误:

/project/src/knotdb/knot-2.3.1/missing: line 81: aclocal-1.15: command not found
WARNING: 'aclocal-1.15' is missing on your system.
         You should only need it if you modified 'acinclude.m4' or
         'configure.ac' or m4 files included by 'configure.ac'.
         The 'aclocal' program is part of the GNU Automake package:
         <http://www.gnu.org/software/automake>
         It also requires GNU Autoconf, GNU m4 and Perl in order to run:
         <http://www.gnu.org/software/autoconf>
         <http://www.gnu.org/software/m4/>
         <http://www.perl.org/>

Continue Reading →

记一个asio实现代理功能的设计思路

23 Jul 2018 | C/CPP, asio |

问题描述

最近在设计一个类似shadowsocks的小东西,在写local部分的时候,考虑了一下这个问题。这个设计场景非常简单:local proxy监听本地端口,一旦有client连接,则会创建一个对远端固定server的连接,将client的数据经过加密后,转发到server上;同时,从server上收到的数据,也会经过解密后转发给client。

Continue Reading →

char类型的一个小坑

06 Dec 2017 | C/CPP |

我们知道,在C中,整数类型(short,int,long)分为有符号和无符号两种,以int为例,单纯一个int代表有符号整型signed int,这里signed可以省略;无符号整型需要显示指明unsigned int

然而char是个例外。当然,C语言中,字符类型也分signed charunsigned char,然而单写char的时候,究竟是有没有符号的?答案是不确定。

Continue Reading →

1 2 3