月度归档:2014年11月

[linux奇技淫巧] 用户态线程coroutine

Coroutine即教科书上提到的“协程”,可以认为是用户态的线程,在它看来thread就是CPU。

在一个thread内可以启动任意多个协程,它们放佛是在同一个“CPU”上运行的多个线程,而与线程的最大不同是,它并非”抢占式“的,因此它让出“CPU”的唯一方式是自己主动放弃执行,保存现场后跳转到其他协程执行。

协程的切换开销远远小于内核对于线程的切换开销,因此对于IO密集型的程序,使用协程的优势在于用户可以像写同步IO一样,无需关心IO异步接口的细节。封装等待IO返回的逻辑,跳转到coroutine库进行调度。减小使用多个线程做同步IO带来的内核大量线程切换的开销。

linux下的swapcontext系列函数提供了协程上下文创建和切换的封装,使用这一组函数可以自己实现简单的coroutine库,使用一个协程作为调度器,其他协程让出“CPU”时都先跳转到调度器,由调度器决定跳转到哪个等待调度的协程继续工作,以此实现包括启动、切换、退出协程的逻辑。

swapcontext的问题是内部调用了内核的锁,造成性能不佳,这里可以使用_longjmp替代swapcontext来优化性能,但是由于_longjmp并未提供创建协程上下文的封装,自己手动构建的过程极其反人类,一个取巧的办法是使用makecontext/swapcontext来构建协程上下文并执行第一次跳转,后续的跳转则使用_longjmp。

一个简单的coroutine例子可以参考我的github。

https://github.com/kayaklee/uthread

Loading

[C/C++奇技淫巧] 变长宏参数的个数

备忘一个宏的奇技淫巧,类似打印日志,RPC封装等无法使用C++0x变长模板参数的情况下,是个不错的选择

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define ARG_COUNT_P1_(\
  _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) \
  N

#define ARG_COUNT_P2_ \
  9, 8, 7, 6, 5, 4, 3, 2, 1, 0

#define ARG_COUNT_(...) \
  ARG_COUNT_P1_(__VA_ARGS__)

#define ARG_COUNT(...) \
  ARG_COUNT_(_, ##__VA_ARGS__, ARG_COUNT_P2_)

#define M_CAT(a, b) M_CAT_(a, b)
#define M_CAT_(a, b) a##b

#define VA_F(...) \
  M_CAT(func, ARG_COUNT(__VA_ARGS__)) (__VA_ARGS__)

#define func(a)   fprintf(stdout, "arg:%ld\t", a);
#define func0()   fprintf(stdout, "func end\n\n");
#define func1(a)  func(a); func0();
#define func2(a, ...) func(a); func1(__VA_ARGS__);
#define func3(a, ...) func(a); func2(__VA_ARGS__);
#define func4(a, ...) func(a); func3(__VA_ARGS__);
#define func5(a, ...) func(a); func4(__VA_ARGS__);
#define func6(a, ...) func(a); func5(__VA_ARGS__);
#define func7(a, ...) func(a); func6(__VA_ARGS__);
#define func8(a, ...) func(a); func7(__VA_ARGS__);
#define func9(a, ...) func(a); func8(__VA_ARGS__);
#define func10(a, ...) func(a); func9(__VA_ARGS__);

int main(int argc, char **argv)
{
  fprintf(stdout, "arg=%ld\n", ARG_COUNT());
  fprintf(stdout, "arg=%ld\n", ARG_COUNT(1));
  fprintf(stdout, "arg=%ld\n", ARG_COUNT(1,2));
  fprintf(stdout, "arg=%ld\n", ARG_COUNT(1,2,3));
  fprintf(stdout, "arg=%ld\n", ARG_COUNT(1,2,3,4));
  fprintf(stdout, "arg=%ld\n", ARG_COUNT(1,2,3,4,5));
  fprintf(stdout, "arg=%ld\n", ARG_COUNT(1,2,3,4,5,6));
  fprintf(stdout, "arg=%ld\n", ARG_COUNT(1,2,3,4,5,6,7));
  fprintf(stdout, "arg=%ld\n", ARG_COUNT(1,2,3,4,5,6,7,8));
  fprintf(stdout, "arg=%ld\n", ARG_COUNT(1,2,3,4,5,6,7,8,9));
  fprintf(stdout, "arg=%ld\n", ARG_COUNT(1,2,3,4,5,6,7,8,9,10));
  fprintf(stdout, "arg=%ld\n", ARG_COUNT(1,2,3,4,5,6,7,8,9,10,11));

  VA_F();
  VA_F(1);
  VA_F(1,2);
  VA_F(1,2,3);
  VA_F(1,2,3,4);
  VA_F(1,2,3,4,5);
  VA_F(1,2,3,4,5,6);
  VA_F(1,2,3,4,5,6,7);
  VA_F(1,2,3,4,5,6,7,8);
  VA_F(1,2,3,4,5,6,7,8,9);
  VA_F(1,2,3,4,5,6,7,8,9,10);
  //VA_F(1,2,3,4,5,6,7,8,9,10,11);
}

 

Loading

Oceanbase内存事务引擎

摘要 OceanBase是一个分布式可扩展的关系数据库,采用基线静态数据与动态增量数据分离存储的架构设计.其内存事务引擎提供了动态数据的存储、写入和查询服务,用户写入的数据被存储在内存中称为Memtable的数据结构中.Memtable及其周边的事务管理结构共同组成了内存数据库引擎,来实现事务的ACID特性.在事务引擎中,通过多版本的并发控制技术实现读写相互不阻塞,实现只读事务满足“快照隔离”级别;通过经典的行锁方式实现多个写之间的并发控制,实现最高满足“已提交读”的事务隔离级别.

关键词关系数据库   分布式系统   事务   互联网

Abstract: OceanBase is a distributed scalable relational database.Its storage architecture is designed by separating baseline static data and increment dynamic data, whose memory transaction engine, namely Memtable, provide dynamic data storage, write, and query, clients wrote data to the in-memory data structure. Memtable and some transaction management structures together form the in-memory database engine, which can achieve the transaction ACID properties. By based multi-version concurrency control techniques to prevent reading and writing from blocking each other to achieve read only transactions to meet the“snapshot isolation”level; Provide multi-write concurrency control by using classic row lock technology to meet the“read committed”transaction isolation level.

Key wordsrelational database system   distributed system   transaction   internet

http://xblk.ecnu.edu.cn/CN/article/downloadArticleFile.do?attachType=PDF&id=25015

Loading