Intelligence without ambition is a bird without wings.

2016-11-07
mount

实例

  • 重新加载/etc/fstab

    mount -a
    
阅读此文

2016-11-04
ls

选项

  • -1

    一个一行

  • –file-type

    跟-F类似,但是普通文件不加*

  • -Z, –context

    查看SELinux

阅读此文

2016-11-02
C/C++中单个操作的时间估计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
Bit Operations:
i1>>1 2.04
i1<<1 2.11
i1>>3 2.1

Int Operations:
i1++ 2.43
i1 = i2 + i3 2.09
i1 = i2 - i3 2.13
i1 = i2 * i3 2.11
i1 = i2 / i3 3.3
i1 = i2 % i3 3.33

Float Operations:
f1 = f2 + f3 2.1
f1 = f2 - f3 2.13
f1 = f2 * f3 2.1
f1 = f2 / f3 2.36

Double Operations:
d1 = d2 + d3 2.12
d1 = d2 - d3 2.09
d1 = d2 * d3 2.14
d1 = d2 / d3 4.75

Numeric Conversions:
i1=(int)f1 2.36
i1=(int)d1 2.37
f1=(float)i1 2.34

Math Functions:
i1 = rand() 9.02
f1 = log(f2) 17.51
f1 = exp(f2) 16.26
f1 = sin(f2) 16.06
f1 = cos(f2) 15.65
f1 = sqrt(f2) 5.3

Fun Call:
fun1() 2.13
i1 = fun2() 2.16
i1 = fun3(i1) 2.44
i1 = fun4(i1, i2, i3) 2.8
if ( i1 == 5) 2.02
if ( i1 > 5) 2.03
if ( i1 != 5) 2.03

Malloc:
free(malloc(8)) 23.65

String Functinos:
i1 = strlen(str1) 2.97
strcpy(str2, str1) 4.03
i1 = strcmp(str2, str1) 2.98

String/Number Conversions:
i1 = atoi("12345") 17.61
sscanf("12345", "%d", &i1) 88.85
sprintf(s, "%d", i) 83.72
f1 = atof("123.45") 105.77
sscanf("123.45", "%f", &f1) 196.67
sprintf(s, "%6.2f", 123.45) 401.93

Input/Ouput:
fprintf(fp, "%d\n", i1) 108.04

Mutex Operations:
pthread_mutex_lock(&mutex_);pthread_mutex_unlock(&mutex_) 3.99

参考

  1. http://mingxinglai.com/cn/2012/12/estimate-value-of-time-in-c/
阅读此文

2016-11-02
redis.conf

redis.conf 配置项说明如下:

  1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程
    daemonize no
  2. 当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定
    pidfile /var/run/redis.pid
  3. 指定Redis监听端口,默认端口为6379,作者在自己的一篇博文中解释了为什么选用6379作为默认端口,因为6379在手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字
    port 6379
  4. 绑定的主机地址
    bind 127.0.0.1
    5.当 客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能
    timeout 300
  5. 指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose
    loglevel verbose
  6. 日志记录方式,默认为标准输出,如果配置Redis为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给/dev/null
    logfile stdout
  7. 设置数据库的数量,默认数据库为0,可以使用SELECT 命令在连接上指定数据库id
    databases 16
  8. 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合
    save
    Redis默认配置文件中提供了三个条件:
    save 900 1
    save 300 10
    save 60 10000
    分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。

  9. 指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大
    rdbcompression yes

  10. 指定本地数据库文件名,默认值为dump.rdb
    dbfilename dump.rdb
  11. 指定本地数据库存放目录
    dir ./
  12. 设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步
    slaveof
  13. 当master服务设置了密码保护时,slav服务连接master的密码
    masterauth
  14. 设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH 命令提供密码,默认关闭
    requirepass foobared
  15. 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息
    maxclients 128
  16. 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区
    maxmemory
  17. 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no
    appendonly no
  18. 指定更新日志文件名,默认为appendonly.aof
    appendfilename appendonly.aof
  19. 指定更新日志条件,共有3个可选值:
    no:表示等操作系统进行数据缓存同步到磁盘(快)
    always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
    everysec:表示每秒同步一次(折衷,默认值)
    appendfsync everysec

  20. 指定是否启用虚拟内存机制,默认值为no,简单的介绍一下,VM机制将数据分页存放,由Redis将访问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章我会仔细分析Redis的VM机制)
    vm-enabled no

  21. 虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享
    vm-swap-file /tmp/redis.swap
  22. 将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的(Redis的索引数据 就是keys),也就是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0
    vm-max-memory 0
  23. Redis swap文件分成了很多的page,一个对象可以保存在多个page上面,但一个page上不能被多个对象共享,vm-page-size是要根据存储的 数据大小来设定的,作者建议如果存储很多小对象,page大小最好设置为32或者64bytes;如果存储很大大对象,则可以使用更大的page,如果不 确定,就使用默认值
    vm-page-size 32
  24. 设置swap文件中的page数量,由于页表(一种表示页面空闲或使用的bitmap)是在放在内存中的,,在磁盘上每8个pages将消耗1byte的内存。
    vm-pages 134217728
  25. 设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4
    vm-max-threads 4
  26. 设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启
    glueoutputbuf yes
  27. 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法
    hash-max-zipmap-entries 64
    hash-max-zipmap-value 512
  28. 指定是否激活重置哈希,默认为开启(后面在介绍Redis的哈希算法时具体介绍)
    activerehashing yes
  29. 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件
    include /path/to/local.conf
阅读此文

2016-11-01
systemd-service

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[Unit] # 基本要素
Description=A high performance web server and a reverse proxy server # 描述
After=network.target # 依赖

[Service] # 说明本文件描述的是daemon
Type=forking
PIDFile=/run/nginx.pid # 用来追踪主进程
ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;' # 启动前执行
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;' # 启动
ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload # 重新加载配置文件
ExecStop=/usr/sbin/nginx -s quit # 停止命令

[Install] # 当执行install命令时,用来说明指定target依赖本服务
WantedBy=multi-user.target

Service

  • Type

    用来说明本服务类型

    • simple[默认] 不调用fork

    • forking 该服务是传统型unix daemon,会调用fork

  • PIDFile

    指定PID文件绝对路径,当Type=forking时,必须设置此项,systemd通过该文件来追踪服务主进程,以便管理

  • Restart

    指定服务进程自动重启的条件。

    • no:默认选项,服务不会被systemd自动重启。
    • on-success:当服务进程成功退出后重启(exit code=0,signals SIGHUP, SIGINT, SIGTERM or SIGPIPE, and additionally, 或SuccessExitStatus=选项指定的退出信号)。
    • on-failure:服务进程不正常退出时进行重启(exit code 为非0,或被信号中断)。
    • on-abnormal:服务进程被信号中断时进行重启。
    • no-watchdog:watchdog观测到服务进程过期后重启服务。
    • no-abort:进程被未捕获的信号中断时将进行重启。
    • always:服务在无论何种情况退出后或者超时时总是重启。

参考

  1. https://www.freedesktop.org/software/systemd/man/systemd.service.html
  2. http://fangpeishi.com/systemd_chapter2.html
  3. https://wiki.archlinux.org/index.php/systemd_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)#.E7.BC.96.E5.86.99.E5.8D.95.E5.85.83.E6.96.87.E4.BB.B6
阅读此文

2016-11-01
systemctl

配置文件目录

  1. /etc/systemd/system/

  2. /usr/lib/systemd/system/

常用命令

  • 重新载入服务(当修过过服务文件后)

    systemctl daemon-reload
    
  • 查看服务状态

    systemctl status <service>
    
  • 查看服务文件

    systemctl cat <service>
    
  • 启动服务

    systemctl start <service>
    
  • 停止服务

    systemctl stop <service>
    
  • 重启

    systemctl restart <service>
    
  • 开机启动

    systemctl enable <service>
    
  • 查看依赖

    systemctl list-dependencies <service>
    
阅读此文

2016-10-28
C++-NULL

NULL

  • 在C/C++中,NULL是一个特殊的常量,可以被赋值(隐式转换)给任意指针类型!

  • 在C中,NULL被定义成一个0值常量表达式或者该表达式被转型为void*,具体由实现决定
    但语法上允许下面用法

    1
    2
    int *pi1 = 0; // ok
    int *pi2 = (void*)0; // ok

    在C++11之前,32位系统中,NULL被定义成0,64位被定义为0LL,这样在一定场景下会导致歧义!

    C++11之后采用nullptr,不支持(void*)0

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #ifndef NULL
    #ifdef __cplusplus
    #ifndef _WIN64
    #define NULL 0 // 32bit
    #else
    #define NULL 0LL // 64bit
    #endif /* W64 */
    #else
    #define NULL ((void *)0)
    #endif
    #endif

    int *pi1 = 0; // ok
    int *pi2 = (void*)0; // error!
    int *pi3 = 1; // error!
    void DoSomething(int x);
    void DoSomething(char* x);
    DoSomething(NULL); // g++ 5.1.0: error: call of overloaded 'DoSomething(NULL)' is ambiguous

    std::vector<int*> v(10);
    // 模板根据NULL推断类型为long long int,而v对应的却是int*!
    std::fill(v.begin(), v.end(), NULL); // error: error: invalid conversion from 'long long int' to 'int*'

void*

在C中,void*从或者向其他类型指针隐式转换,但在C++中,不允许void*隐式转换为其他类型指针!

1
2
3
void *pv;
int *pi = pv; // C中合法,C++中不合法
pv = pi; //
1
2
3
4
void *pv;
// int *pi = pv; // error!
int *pi = reinterpret_cast<int*>(pv);
pv = pi;

为什么C++中采用#define NULL 0,而不支持#define NULL ((void *)0)呢?

在C中,假设开发人员知道他们所做的事,允许void*隐式转换是为了方便程序开发。

而在C++中,为了保证类型安全,不建议使用C中的强制类型转换,以及void*隐式转换(从语法层禁止!)
因为C++中,为了支持类,多态,类型之间任意转换,是很容易导致错误的!

假设允许void*隐式转换:

1
2
void *pa = new A;
B *pb = pa;

类似这样的代码不会发出任何警告,而这样的错误定位起来非常麻烦!

参考

  1. Why must I use a cast to convert from void*?
  2. http://stackoverflow.com/questions/7016861/why-are-null-pointers-defined-differently-in-c-and-c
  3. http://en.cppreference.com/w/c/language/conversion#Pointer_conversions
  4. http://en.cppreference.com/w/cpp/types/NULL
  5. http://softwareengineering.stackexchange.com/questions/275712/why-arent-void-s-implicitly-cast-in-c
  6. C++ 4.10.1
阅读此文

2016-10-28
C++11-initializer_list

要点

  • 由编译器在编译阶段解释该语法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    template<class _E>
    class initializer_list
    {
    public:
    typedef _E value_type;
    typedef const _E& reference;
    typedef const _E& const_reference;
    typedef size_t size_type;
    typedef const _E* iterator;
    typedef const _E* const_iterator;

    private:
    iterator _M_array;
    size_type _M_len;

    // The compiler can call a private constructor.
    constexpr initializer_list(const_iterator __a, size_type __l)
    : _M_array(__a), _M_len(__l) { }
  • 拷贝该对象,并不会复制底层数据,因为是通过指针引用的!

  • 可以用来定义构造函数(初始化列表构造函数)

    myclass(initializer_list<int>);
    
  • 可以用来初始化STL,因为C++11之后,STL类增加了初始化列表构造函数

    1
    2
    3
    4
    5
    6
    vector(initializer_list<value_type> __l,
    const allocator_type& __a = allocator_type())
    : _Base(__a)
    {
    _M_range_initialize(__l.begin(), __l.end(), random_access_iterator_tag());
    }

参考

  1. http://en.cppreference.com/w/cpp/utility/initializer_list
  2. http://www.cplusplus.com/reference/initializer_list/initializer_list/?kw=initializer_list
阅读此文

2016-10-27
sudo

  • 不要求tty

    sudo vi /etc/sudoers
    Defaults requiretty`=>`Defaults !requiretty
    
阅读此文

2016-10-27
virtualbox

  • 关闭guest自动与host校时

    sudo systemctl status vboxadd-service
    
阅读此文