c++ - segmentation fault

原因

  • 访问空指针
  • 访问不可访问的内存
    • 访问不可访问的变量 / 已经不在可访问作用域的变量,即便 gdb 调试可以展示变量值

案例

1
2
3
4
5
6
# 1. 访问已经回收的临时变量
使用 seastar 时,调用返回 future 方法的方法,参数包含局部变量。在执行 then 回调时,局部变量已经不可访问(使用 gdb 调试仍可展示数值)。
解决方法是使用 seastar::do_with(std::move(v), [](V &v) { ... })

# 2. 未加 return 值导致 std::function 析构
定义的方法返回值类型不为 void,但是没有 return 语句,定义 std::function 对象,在析构时报 segmentation fault

Lambda

shared_ptr

shared_ptr 引用导致的内存非法访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class A {
public:
int a;
};

std::function<void()> fun() {
std::shared_ptr<A> sa = std::make_shared<A>();
sa->a = 2;
auto f = [&] {
std::cout << "sa-> " << sa->a << std::endl;
sa->a = 1;
};
return f;
}

void test() {
std::cout << "----- in test -----" << std::endl;
fun()();
std::cout << "----- out test -----" << std::endl;
}

调用

1
2
3
4
int main() {
test();
return 0;
}

输出

1
2
3
4
----- in test -----
sa-> 281314120

Process finished with exit code 138 (interrupted by signal 10: SIGBUS)

原因

lambda 表达式使用引用访问局部变量,在 fun() 返回 lambda 表达式对象时,局部变量 sa 已被释放,在 test 中执行 lambda 表达式时会访问已被释放的内存。

解决

使用拷贝替换引用,增加引用计数。

1
2
3
4
5
6
7
8
9
std::function<void()> fun() {
std::shared_ptr<A> sa = std::make_shared<A>();
sa->a = 2;
auto f = [&, sa] {
std::cout << "sa-> " << sa->a << std::endl;
sa->a = 1;
};
return f;
}

输出

1
2
3
4
5
----- in test -----
sa-> 2
----- out test -----

Process finished with exit code 0

ftp client usage

1
2
3
4
5
6
7
8
9
10
11
Usage: { ftp | pftp } [-46pinegvtd] [hostname]
-4: use IPv4 addresses only
-6: use IPv6, nothing else
-p: enable passive mode (default for pftp)
-i: turn off prompting during mget
-n: inhibit auto-login
-e: disable readline support, if present
-g: disable filename globbing
-v: verbose mode
-t: enable packet tracing [nonfunctional]
-d: enable debugging

登录

1
2
$ ftp
ftp> open {ip}

gdb

忽略 SIGNAL

1
Signal: SIG34 (Real-time event 34)

在使用 gdb 调试时,如果频繁被信号中断,可屏蔽对应信号,以 SIG34 为例。

1
2
# file: ~/.gdbinit
handle SIG34 nostop noprint pass noignore
1
2
handle SIG34 nostop noprint pass noignore
handle SIG35 nostop noprint pass noignore

调试程序

1
2
3
4
$ gdb <program>

# 为程序添加参数
$ gdb --args program <args>

启动程序

1
$ gdb -ex=r --args /path/to/program arg1 arg2 # -ex=r => -ex=run
1
2
$ gdb /path/to/program
(gdb) run {args}

调试 core 文件

1
2
3
4
$ gdb <program> <core-file>
$ gdb <program> -c <core-file>
$ gdb <program>
(gdb) core <core-file>

命令

参考一

常用命令

b

1
2
3
4
5
6
7
8
# b, 断点相关
b main - Puts a breakpoint at the beginning of the program
b - Puts a breakpoint at the current line
b N - Puts a breakpoint at line N
b +N - Puts a breakpoint N lines down from the current line
b fn - Puts a breakpoint at the beginning of function "fn"
d N - Deletes breakpoint number N
info break - list breakpoints
1
2
3
4
5
6
7
8
9
10
11
12
r - Runs the program until a breakpoint or error
c - Continues running the program until the next breakpoint or error
f - Runs until the current function is finished
s - Runs the next line of the program
s N - Runs the next N lines of the program
n - Like s, but it does not step into functions
u N - Runs until you get N lines in front of the current line
p var - Prints the current value of the variable "var"
bt - Prints a stack trace
u - Goes up a level in the stack
d - Goes down a level in the stack
q - Quits gdb

p

打印给定的表达式

1
2
3
4
5
print [Expression]
print $[Previous value number]
print {[Type]}[Address]
print [First element]@[Element count]
print /[Format] [Expression]
  • Expression
    • 变量
    • 寄存器,$eax 等
    • 伪寄存器,$pc 等
  • Format
    • 合法的格式符
      • o - octal
      • x - hexadecimal
      • u - unsigned decimal
      • t - binary
      • f - floating point
      • a - address
      • c - char
      • s - string

注意

  • 打印本地变量时,需要确保选定了正确的帧(frame)

参考一

x

使用指定的格式,打印给定地址的内存内容。

1
2
3
4
x [Address expression]
x /[Format] [Address expression]
x /[Length][Format] [Address expression]
x
  • Address expression
    • 寄存器,$eip
    • 伪寄存器地址,$pc
  • Format
    • 格式
      • o - octal
      • x - hexadecimal
      • d - decimal
      • u - unsigned decimal
      • t - binary
      • f - floating point
      • a - address
      • c - char
      • s - string
      • i - instruction
    • 大小修饰符(size modifiers)
      • b - byte
      • h - halfword (16-bit value)
      • w - word (32-bit value)
      • g - giant word (64-bit value)
  • Length
    • 指定打印的元素个数

参考一

帧相关

1
2
3
(gdb) f n       # 选中第 n 个帧
(gdb) up # 上一个帧
(gdb) down # 下一个帧

打印变量

1
2
3
4
5
6
7
# 查看所有调用栈
bt
# 选中某个栈
select-frame <frame-no>

# 打印变量
display <variable-name>

列出变量

1
2
3
4
5
6
# 查看本地变量
info locals
# 查看全局变量
info variables
# 查看参数
info args

分类型打印

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 打印 char *
(gdb) p *(char**)0x21d4b4910

# map 相关
(gdb) p m._M_h
(gdb) p (m._M_h._M_bbegin._M_node._M_nxt)
(gdb) p m._M_h._M_buckets
(gdb) p m._M_h._M_buckets[0]

# vector 相关
(gdb) p *(v._M_impl._M_start+4)
(gdb) p *(v._M_impl._M_start+4)._M_ptr.name # name: struct field

# 智能指针
(gdb) p sptr._M_ptr->name # name: struct field

Vector

1
p *(*(m._M_impl._M_start+6)._M_impl._M_start) # vector<vector> 打印第 7 个元素 (vector)

Pretty Printer

Pretty Printer 功能是否支持是在 gdb 编译时,根据编译选项决定的。在编译时需要添加编译参数 --with-python 来启用 Pretty Printer。下面的命令可以查看是否开启。

1
2
3
4
5
6
7
$ gdb -config
This GDB was configured as follows:
configure --host=x86_64-pc-linux-gnu --target=x86_64-pc-linux-gnu
...
--without-python
--without-python-libdir
...

指定自定义的 python 路径,要指定到 python 二进制文件。

1
--without-python=/path/to/python/bin/python3

低版本的 python 在 configure 时会校验不通过,建议使用较新版本的 python3。

pretty printer 使用手册参考这里

多线程

1
2
3
4
(gdb) info threads           # 打印所有线程信息
(gdb) info threads {thread-no}... # 打印指定线程信息
(gdb) thread {thread-no} # 切换到线程
(gdb) thread apply all bt # 在所有线程打印调用栈信息

常见问题

gdb 卡住

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Reading symbols from <bin>...done.
[New LWP 19134]
[New LWP 19669]
[New LWP 19672]
[New LWP 19670]
[New LWP 19200]
[New LWP 19668]
[New LWP 19667]
[New LWP 19673]
[New LWP 19676]
[New LWP 19680]
[New LWP 19197]
[New LWP 19671]
[New LWP 19674]

yum 同样卡住,使用 ps aux | grep yumkill -9 之后,恢复正常。

断点

Attach 方式

1
2
3
4
5
# 定义断点文件 bp.info
break main.cpp:15

# attach 进程
gdb attach 10232 -x bp.info

命令

1

常见问题

value optimized out

1
2
3
4
5
6
# build type = debug
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_DEBUG} -O0")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_DEBUG} -O0")

参考

lldb

配置

忽略 SIGNAL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
process handle -p true -s false -n false SIGINT
process handle -p true -s false -n false SIGUSR1
process handle -p true -s false -n false SIGUSR2
process handle -p false -s false -n false SIGRTMIN
process handle -p false -s false -n false SIGRTMIN+1
process handle -p true -s false -n false SIGRTMIN+11
process handle -p true -s false -n false SIGRTMIN+12
process handle -p true -s false -n false SIGHUP
process handle -p true -s false -n false SIGQUIT
process handle -p true -s false -n false SIGILL
process handle -p true -s false -n false SIGABRT
process handle -p true -s false -n false SIGFPE
process handle -p true -s false -n false SIGSEGV
process handle -p true -s false -n false SIGALRM
process handle -p true -s false -n false SIGCONT
process handle -p true -s false -n false SIGSTOP
process handle -p true -s false -n false SIGTSTP
process handle -p true -s false -n false SIGTTIN
process handle -p true -s false -n false SIGTTOU
process handle -p true -s false -n false SIGTERM
# 或添加在配置文件 ~/.lldbinit 中

Signals

gdb 和 lldb 的 signal 有些差异,比如 gdb 中的 SIG34 在 lldb 中是 SIGRTMIN,SIG35 对应 SIGRTMIN+1。

LLDB

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
AddSignal(1,      "SIGHUP",       false,    true,   true,   "hangup");
AddSignal(2, "SIGINT", true, true, true, "interrupt");
AddSignal(3, "SIGQUIT", false, true, true, "quit");
AddSignal(4, "SIGILL", false, true, true, "illegal instruction");
AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)");
AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT");
AddSignal(7, "SIGBUS", false, true, true, "bus error");
AddSignal(8, "SIGFPE", false, true, true, "floating point exception");
AddSignal(9, "SIGKILL", false, true, true, "kill");
AddSignal(10, "SIGUSR1", false, true, true, "user defined signal 1");
AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation");
AddSignal(12, "SIGUSR2", false, true, true, "user defined signal 2");
AddSignal(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed");
AddSignal(14, "SIGALRM", false, false, false, "alarm");
AddSignal(15, "SIGTERM", false, true, true, "termination requested");
AddSignal(16, "SIGSTKFLT", false, true, true, "stack fault");
AddSignal(17, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD");
AddSignal(18, "SIGCONT", false, false, true, "process continue");
AddSignal(19, "SIGSTOP", true, true, true, "process stop");
AddSignal(20, "SIGTSTP", false, true, true, "tty stop");
AddSignal(21, "SIGTTIN", false, true, true, "background tty read");
AddSignal(22, "SIGTTOU", false, true, true, "background tty write");
AddSignal(23, "SIGURG", false, true, true, "urgent data on socket");
AddSignal(24, "SIGXCPU", false, true, true, "CPU resource exceeded");
AddSignal(25, "SIGXFSZ", false, true, true, "file size limit exceeded");
AddSignal(26, "SIGVTALRM", false, true, true, "virtual time alarm");
AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm");
AddSignal(28, "SIGWINCH", false, true, true, "window size changes");
AddSignal(29, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL");
AddSignal(30, "SIGPWR", false, true, true, "power failure");
AddSignal(31, "SIGSYS", false, true, true, "invalid system call");
AddSignal(32, "SIG32", false, false, false, "threading library internal signal 1");
AddSignal(33, "SIG33", false, false, false, "threading library internal signal 2");
AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0");
AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1");
AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2");
AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3");
AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4");
AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5");
AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6");
AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7");
AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8");
AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9");
AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10");
AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11");
AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12");
AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13");
AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14");
AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15");
AddSignal(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output
AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17");
AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18");
AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19");
AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20");
AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21");
AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22");
AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23");
AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24");
AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25");
AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26");
AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27");
AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28");
AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29");
AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30");

GDB

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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
AddSignal(1,      "SIGHUP",       false,    true,   true,   "hangup");
AddSignal(2, "SIGINT", true, true, true, "interrupt");
AddSignal(3, "SIGQUIT", false, true, true, "quit");
AddSignal(4, "SIGILL", false, true, true, "illegal instruction");
AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)");
AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT");
AddSignal(7, "SIGEMT", false, true, true, "emulation trap");
AddSignal(8, "SIGFPE", false, true, true, "floating point exception");
AddSignal(9, "SIGKILL", false, true, true, "kill");
AddSignal(10, "SIGBUS", false, true, true, "bus error");
AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation");
AddSignal(12, "SIGSYS", false, true, true, "invalid system call");
AddSignal(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed");
AddSignal(14, "SIGALRM", false, false, false, "alarm");
AddSignal(15, "SIGTERM", false, true, true, "termination requested");
AddSignal(16, "SIGURG", false, true, true, "urgent data on socket");
AddSignal(17, "SIGSTOP", true, true, true, "process stop");
AddSignal(18, "SIGTSTP", false, true, true, "tty stop");
AddSignal(19, "SIGCONT", false, false, true, "process continue");
AddSignal(20, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD");
AddSignal(21, "SIGTTIN", false, true, true, "background tty read");
AddSignal(22, "SIGTTOU", false, true, true, "background tty write");
AddSignal(23, "SIGIO", false, true, true, "input/output ready/Pollable event");
AddSignal(24, "SIGXCPU", false, true, true, "CPU resource exceeded");
AddSignal(25, "SIGXFSZ", false, true, true, "file size limit exceeded");
AddSignal(26, "SIGVTALRM", false, true, true, "virtual time alarm");
AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm");
AddSignal(28, "SIGWINCH", false, true, true, "window size changes");
AddSignal(29, "SIGLOST", false, true, true, "resource lost");
AddSignal(30, "SIGUSR1", false, true, true, "user defined signal 1");
AddSignal(31, "SIGUSR2", false, true, true, "user defined signal 2");
AddSignal(32, "SIGPWR", false, true, true, "power failure");
AddSignal(33, "SIGPOLL", false, true, true, "pollable event");
AddSignal(34, "SIGWIND", false, true, true, "SIGWIND");
AddSignal(35, "SIGPHONE", false, true, true, "SIGPHONE");
AddSignal(36, "SIGWAITING", false, true, true, "process's LWPs are blocked");
AddSignal(37, "SIGLWP", false, true, true, "signal LWP");
AddSignal(38, "SIGDANGER", false, true, true, "swap space dangerously low");
AddSignal(39, "SIGGRANT", false, true, true, "monitor mode granted");
AddSignal(40, "SIGRETRACT", false, true, true, "need to relinquish monitor mode");
AddSignal(41, "SIGMSG", false, true, true, "monitor mode data available");
AddSignal(42, "SIGSOUND", false, true, true, "sound completed");
AddSignal(43, "SIGSAK", false, true, true, "secure attention");
AddSignal(44, "SIGPRIO", false, true, true, "SIGPRIO");
AddSignal(45, "SIG33", false, false, false, "real-time event 33");
AddSignal(46, "SIG34", false, false, false, "real-time event 34");
AddSignal(47, "SIG35", false, false, false, "real-time event 35");
AddSignal(48, "SIG36", false, false, false, "real-time event 36");
AddSignal(49, "SIG37", false, false, false, "real-time event 37");
AddSignal(50, "SIG38", false, false, false, "real-time event 38");
AddSignal(51, "SIG39", false, false, false, "real-time event 39");
AddSignal(52, "SIG40", false, false, false, "real-time event 40");
AddSignal(53, "SIG41", false, false, false, "real-time event 41");
AddSignal(54, "SIG42", false, false, false, "real-time event 42");
AddSignal(55, "SIG43", false, false, false, "real-time event 43");
AddSignal(56, "SIG44", false, false, false, "real-time event 44");
AddSignal(57, "SIG45", false, false, false, "real-time event 45");
AddSignal(58, "SIG46", false, false, false, "real-time event 46");
AddSignal(59, "SIG47", false, false, false, "real-time event 47");
AddSignal(60, "SIG48", false, false, false, "real-time event 48");
AddSignal(61, "SIG49", false, false, false, "real-time event 49");
AddSignal(62, "SIG50", false, false, false, "real-time event 50");
AddSignal(63, "SIG51", false, false, false, "real-time event 51");
AddSignal(64, "SIG52", false, false, false, "real-time event 52");
AddSignal(65, "SIG53", false, false, false, "real-time event 53");
AddSignal(66, "SIG54", false, false, false, "real-time event 54");
AddSignal(67, "SIG55", false, false, false, "real-time event 55");
AddSignal(68, "SIG56", false, false, false, "real-time event 56");
AddSignal(69, "SIG57", false, false, false, "real-time event 57");
AddSignal(70, "SIG58", false, false, false, "real-time event 58");
AddSignal(71, "SIG59", false, false, false, "real-time event 59");
AddSignal(72, "SIG60", false, false, false, "real-time event 60");
AddSignal(73, "SIG61", false, false, false, "real-time event 61");
AddSignal(74, "SIG62", false, false, false, "real-time event 62");
AddSignal(75, "SIG63", false, false, false, "real-time event 63");
AddSignal(76, "SIGCANCEL", false, true, true, "LWP internal signal");
AddSignal(77, "SIG32", false, false, false, "real-time event 32");
AddSignal(78, "SIG64", false, false, false, "real-time event 64");
AddSignal(79, "SIG65", false, false, false, "real-time event 65");
AddSignal(80, "SIG66", false, false, false, "real-time event 66");
AddSignal(81, "SIG67", false, false, false, "real-time event 67");
AddSignal(82, "SIG68", false, false, false, "real-time event 68");
AddSignal(83, "SIG69", false, false, false, "real-time event 69");
AddSignal(84, "SIG70", false, false, false, "real-time event 70");
AddSignal(85, "SIG71", false, false, false, "real-time event 71");
AddSignal(86, "SIG72", false, false, false, "real-time event 72");
AddSignal(87, "SIG73", false, false, false, "real-time event 73");
AddSignal(88, "SIG74", false, false, false, "real-time event 74");
AddSignal(89, "SIG75", false, false, false, "real-time event 75");
AddSignal(90, "SIG76", false, false, false, "real-time event 76");
AddSignal(91, "SIG77", false, false, false, "real-time event 77");
AddSignal(92, "SIG78", false, false, false, "real-time event 78");
AddSignal(93, "SIG79", false, false, false, "real-time event 79");
AddSignal(94, "SIG80", false, false, false, "real-time event 80");
AddSignal(95, "SIG81", false, false, false, "real-time event 81");
AddSignal(96, "SIG82", false, false, false, "real-time event 82");
AddSignal(97, "SIG83", false, false, false, "real-time event 83");
AddSignal(98, "SIG84", false, false, false, "real-time event 84");
AddSignal(99, "SIG85", false, false, false, "real-time event 85");
AddSignal(100, "SIG86", false, false, false, "real-time event 86");
AddSignal(101, "SIG87", false, false, false, "real-time event 87");
AddSignal(102, "SIG88", false, false, false, "real-time event 88");
AddSignal(103, "SIG89", false, false, false, "real-time event 89");
AddSignal(104, "SIG90", false, false, false, "real-time event 90");
AddSignal(105, "SIG91", false, false, false, "real-time event 91");
AddSignal(106, "SIG92", false, false, false, "real-time event 92");
AddSignal(107, "SIG93", false, false, false, "real-time event 93");
AddSignal(108, "SIG94", false, false, false, "real-time event 94");
AddSignal(109, "SIG95", false, false, false, "real-time event 95");
AddSignal(110, "SIG96", false, false, false, "real-time event 96");
AddSignal(111, "SIG97", false, false, false, "real-time event 97");
AddSignal(112, "SIG98", false, false, false, "real-time event 98");
AddSignal(113, "SIG99", false, false, false, "real-time event 99");
AddSignal(114, "SIG100", false, false, false, "real-time event 100");
AddSignal(115, "SIG101", false, false, false, "real-time event 101");
AddSignal(116, "SIG102", false, false, false, "real-time event 102");
AddSignal(117, "SIG103", false, false, false, "real-time event 103");
AddSignal(118, "SIG104", false, false, false, "real-time event 104");
AddSignal(119, "SIG105", false, false, false, "real-time event 105");
AddSignal(120, "SIG106", false, false, false, "real-time event 106");
AddSignal(121, "SIG107", false, false, false, "real-time event 107");
AddSignal(122, "SIG108", false, false, false, "real-time event 108");
AddSignal(123, "SIG109", false, false, false, "real-time event 109");
AddSignal(124, "SIG110", false, false, false, "real-time event 110");
AddSignal(125, "SIG111", false, false, false, "real-time event 111");
AddSignal(126, "SIG112", false, false, false, "real-time event 112");
AddSignal(127, "SIG113", false, false, false, "real-time event 113");
AddSignal(128, "SIG114", false, false, false, "real-time event 114");
AddSignal(129, "SIG115", false, false, false, "real-time event 115");
AddSignal(130, "SIG116", false, false, false, "real-time event 116");
AddSignal(131, "SIG117", false, false, false, "real-time event 117");
AddSignal(132, "SIG118", false, false, false, "real-time event 118");
AddSignal(133, "SIG119", false, false, false, "real-time event 119");
AddSignal(134, "SIG120", false, false, false, "real-time event 120");
AddSignal(135, "SIG121", false, false, false, "real-time event 121");
AddSignal(136, "SIG122", false, false, false, "real-time event 122");
AddSignal(137, "SIG123", false, false, false, "real-time event 123");
AddSignal(138, "SIG124", false, false, false, "real-time event 124");
AddSignal(139, "SIG125", false, false, false, "real-time event 125");
AddSignal(140, "SIG126", false, false, false, "real-time event 126");
AddSignal(141, "SIG127", false, false, false, "real-time event 127");
AddSignal(142, "SIGINFO", false, true, true, "information request");
AddSignal(143, "unknown", false, true, true, "unknown signal");
AddSignal(145, "EXC_BAD_ACCESS", false, true, true, "could not access memory");
AddSignal(146, "EXC_BAD_INSTRUCTION", false, true, true, "illegal instruction/operand");
AddSignal(147, "EXC_ARITHMETIC", false, true, true, "arithmetic exception");
AddSignal(148, "EXC_EMULATION", false, true, true, "emulation instruction");
AddSignal(149, "EXC_SOFTWARE", false, true, true, "software generated exception");
AddSignal(150, "EXC_BREAKPOINT", false, true, true, "breakpoint");
AddSignal(151, "SIGLIBRT", false, true, true, "librt internal signal");

命令

查看所有 handle

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
(lldb) process handle
NAME PASS STOP NOTIFY
=========== ===== ===== ======
SIGHUP true true true
SIGINT true false true
SIGQUIT true true true
SIGILL true true true
SIGTRAP false true true
SIGABRT true true true
SIGBUS true false true
SIGFPE true true true
SIGKILL true true true
SIGUSR1 true false true
SIGSEGV true true true
SIGUSR2 true false true
SIGPIPE true true true
SIGALRM true false false
SIGTERM true true true
SIGSTKFLT true true true
SIGCHLD true false true
SIGCONT true false true
SIGSTOP false true true
SIGTSTP true true true
SIGTTIN true true true
SIGTTOU true true true
SIGURG true true true
SIGXCPU true true true
SIGXFSZ true true true
SIGVTALRM true true true
SIGPROF true false false
SIGWINCH true true true
SIGIO true true true
SIGPWR true true true
SIGSYS true true true
SIG32 true false false
SIG33 true false false
SIGRTMIN true false false
SIGRTMIN+1 true false false
SIGRTMIN+2 true false false
SIGRTMIN+3 true false false
SIGRTMIN+4 true false false
SIGRTMIN+5 true false false
SIGRTMIN+6 true false false
SIGRTMIN+7 true false false
SIGRTMIN+8 true false false
SIGRTMIN+9 true false false
SIGRTMIN+10 true false false
SIGRTMIN+11 true false false
SIGRTMIN+12 true false false
SIGRTMIN+13 true false false
SIGRTMIN+14 true false false
SIGRTMIN+15 true false false
SIGRTMAX-14 true false false
SIGRTMAX-13 true false false
SIGRTMAX-12 true false false
SIGRTMAX-11 true false false
SIGRTMAX-10 true false false
SIGRTMAX-9 true false false
SIGRTMAX-8 true false false
SIGRTMAX-7 true false false
SIGRTMAX-6 true false false
SIGRTMAX-5 true false false
SIGRTMAX-4 true false false
SIGRTMAX-3 true false false
SIGRTMAX-2 true false false
SIGRTMAX-1 true false false
SIGRTMAX true false false

mongodb query

进入交互界面

1
$ mongo

查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 查看数据库
> show dbs;
local 0.000GB
test 0.000GB

# 进入数据库
> use test;

# 查看集合
> show collections; # 或者 show tables;

# 查询集合
> db.test.findOne()

# 统计数量
> db.test.count({...})

# 指定字段
db.user.find({"status": 1, "updated": {"$gt" : 1672831786 }}, {updated: 1})

和关系型数据库对应,collections - table,doc - row。

类型查询

可用类型查看这里

1
2
> db.test.findOne({id: {$type: 'int'}})
> db.test.findOne({id: {$not: {$type: 'int'}}})

mongo tools

工具

这里 下载。

  • MongoDB Shell

Mongo Shell

1
2
3
4
5
6
7
8
9
# 下载
$ wget https://downloads.mongodb.com/compass/mongosh-1.1.9-linux-x64.tgz

# 解压
$ tar -xf mongosh-1.1.9-linux-x64.tgz
$ cd mongosh-1.1.9-linux-x64

# 查看帮助
$ ./bin/mongosh -h

参数

1
2
3
4
5
6
7
8
9
# 格式
$ mongosh [options] [db address] [file names (ending in .js or .mongodb)]

# options
-u username
-p password

# example
$ mongosh mongodb://192.168.0.5:9999

读取 secondary 节点

参考 这里这里

When using the legacy mongo shell to connect directly to secondary replica set member, you must run mongo.setReadPref() to enable secondary reads.

When using mongosh to connect directly to a secondary replica set member, you can read from that member if you specify a read preference of either:

1
mongodb://mongos1.example.com,mongos2.example.com/?readPreference=secondary&readPreferenceTags=dc:ny,rack:r1&readPreferenceTags=dc:ny&readPreferenceTags=
1
2
# 连接时添加 readPreference 参数
$ mongosh mongodb://192.168.0.5:9999/?readPreference=secondary

mongoldb

安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# aliyun linux 3
vim /etc/yum.repos.d/mongodb-org-6.0.repo
# 输入如下内容
[mongodb-org-6.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/8/mongodb-org/6.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-6.0.asc

# 安装
sudo yum install -y mongodb-org mongodb-database-tools mongodb-mongsh

# 管理
sudo systemctl start mongod
sudo systemctl status mongod
sudo systemctl enable mongod
sudo systemctl stop mongod
sudo systemctl restart mongod

# 使用 mongo db
mongosh

docker

1
2
docker pull mongo
docker run -itd --name mongo -p 27017:27017 mongo

导出

这里下载 Mongodb Database tools。

1
2
3
4
# 导出
$ mongodump --uri "mongodb://usersname:password@127.0.0.1:27100/dbname?replicaSet=replica_name&authSource=admin" --out "/path/to/save"

$ mongodump --uri "mongodb://127.0.0.1" --out data-dump --db library --collection booksion

导入

1
$ mongorestore --nsInclude=<db>.<table> /path/to/data.bson

操作

文档参考这里

1
2
3
4
5
# 1. 创建数据库. 使用 use 即可创建 database
> use <db-name>

# 2. 创建集合. 使用插入数据语法, 不存在集合则创建
> db.test.insertOne( { x: 1 } );

制作 docker 镜像

[toc]

编写 Dockerfile

示例

1
2
3
4
FROM	centos:7
LABEL maintainer="zhenkai.sun@qq.com"
LABEL version="v0.0.1-centos-7"
RUN yum -y install gcc g++ automake autoconf make git libtool

命令

1
2
3
4
5
6
7
8
FROM  
LABEL 设置元数据(LABEL author=wii email=zhenkai.sun@qq.com)
ARG 设置参数, Dockerfile 内有效
RUN 构建时运行命令
EXPOSE 声明端口
ENV 设置环境变量, 多值空格分隔(ENV PAHT=/usr/bin GOROOT=/data/go/)
CMD 运行容器时运行, 指定默认运行的程序, 程序结束容器退出, 会被 docker run 命令行参数指定的命令覆盖, 仅最后一个生效
ENTRYPOINT 容器运行时运行,需要显式指定 --entrypoint 才会被覆盖, 只有最后一个生效, CMD 会作为 ENTRYPOINT 的参数

构建镜像

1
$ docker build -t sunzhenkai/cmake-external-library .

发布

1
2
3
4
5
6
7
$ docker tag user/prop:latest user/prop:<version/tag>
$ docker login -u <用户名> -p <密码>
$ docker push user/prop:<version/tag>

# 示例
$ docker tag sunzhenkai/cmake-external-library:latest hub.docker.com/sunzhenkai/cmake-external-library:centos7-v0.0.1
$ docker push hub.docker.com/sunzhenkai/cmake-external-library:centos7-v0.0.1

参考

c++ tricks

[toc]

Shuffle

1
2
3
4
5
6
static void shuffle(vector<int>* v) {
srand(9);
for (int n = v->size(); n >= 2; n--) {
swap((*v)[n - 1], (*v)[static_cast<unsigned>(rand()) % n]);
}
}

class 成员初始化

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
$ cat 010.cpp 
#include <iostream>

using namespace std;

class Plm {
public:
struct Arg {
size_t net;
size_t mem;
size_t query;
};
};

int main() {
Plm::Arg arg {
.net = 1,
.mem = 3,
.query = 2
};
cout << arg.net << " " << arg.mem << " " << arg.query << endl;
return 0;
}
$ g++ 010.cpp && ./a.out
1 3 2

parameter pack

1
2
3
4
5
6
7
template<typename... Arguments>
void SampleFunction(Arguments... parameters);

// equals to

template<typename T, typename U>
void SampleFunction(T param1, U param2);
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
bovenson@Dell:~/Git/notes/C++/Code/Learn$ cat 005.cpp 
#include <iostream>

using namespace std;

void fa(int a, int b) {
cout << a << " " << b << endl;
}

template<typename... Args>
void f(Args... args) {
fa((args)...);
fa(args...);
fa(std::forward<Args>(args)...);
// fa(std::forward<Args>((args)...)); // ERROR
}


int main() {
f<int, int>(1, 2); // OK
f(1, 2); // OK
return 0;
}
bovenson@Dell:~/Git/notes/C++/Code/Learn$ g++ 005.cpp && ./a.out
1 2
1 2
1 2
1 2
1 2
1 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
MBP:Learn sunzhenkai$ cat 16.cpp
#include <iostream>
#include <vector>

using namespace std;

template <typename... T>
void f(T... args) {
std::vector<int> v = { args... };
for (auto item : v) {
std::cout << item << std::endl;
}
}

int main() {
f(1, 2, 3, 4, 5);
return 0;
}
MBP:Learn sunzhenkai$ g++ 16.cpp -std=c++11 && ./a.out
1
2
3
4
5

完美转发

无论是T&&、左值引用、右值引用,std::forward都会依照原来的类型完美转发。

省略号语法

Amazing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
MBP:Learn sunzhenkai$ cat 15.cpp
#include <iostream>

using namespace std;

class A { };

class B {
public:
B(A a) {}
};

void fun(B b) {
cout << "OK? OK!" << endl;
}

int main() {
A a;
fun(a);
return 0;
}
MBP:Learn sunzhenkai$ g++ 15.cpp && ./a.out
OK? OK!

c++ tips

[toc]

namespace 别名

1
2
3
4
// 设置 namespase 别名
namespace tcxx = ::apache::thrift::stdcxx;
// 使用
tcxx::function<void()>

引用别名

1
2
using S = ::space::Server;
auto server = S(80)

函数参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
setRouters(std::function<void(seastar::httpd::routes & )> routes) 
{
// ...
}

// 等价的
setRouters(void (*routes)(seastar::httpd::routes &))
{
// ...
routes(...);
}

// lambda
template<typename F>
SafetyRun(F &&func) {
func(...);
}

SafetyRun([...](...) {
...
});

对象成员函数作为参数

参考这里

字符串

分隔字符串

1
2
3
4
5
6
std::string server_address = "127.0.0.1:80";
std::vector<std::string> result;
boost::split(result, server_address, boost::is_any_of(":"));

result.at(0); // 127.0.0.1
result.at(1); // 80

join 字符串

1
2
3
4
// 使用 fmt
#include <fmt/format.h>
// fmt::join(elems, delim)
auto s = fmt::format("{}",fmt::join(elems, delim));

类型转换

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
// string -> int
stoi("80")
# lambda

## lambda 参数

```shell
# 定义接受 lambda 作为参数的函数
## 方式 1
template<typename Func>
void lmb(Func &&f) {
f();
}
## 方式 2
void lmb2(std::function<void()> &&f) {
f();
}

# 调用
lmb([]() {
std::cout << "run lambda" << std::endl;
});
lmb2([]() {
std::cout << "run lambda 2" << std::endl;
});

# 定义变量
auto f = []() {
std::cout << "lambda variable" << std::endl;
};
# 调用
lmb(f);
lmb2(f);

对比

1
2
dynamic_pointer_cast
static_pointer_cast

reinterpret_cast

1
2
void const *const data;
const Record *record = reinterpret_cast<Record*>(data);

static_cast

1
2
void const *const data;
const Record *record = static_cast<Record*>(data);

const_cast

1
2
const Record *data;
Record *record = reinterpret_cast<Record*>(data);

获取变量类型

1
2
3
int c = 0;
std::vector<decltype(c)> cs; // 定义 vector,元素类型和 c 相同
cs.emplace_back(c);

time

1
2
std::chrono::system_clock  // 系统时间
std::chrono::steady_clock // 单调时间,并不能获取系统时间,多用来计算时间差

获取时间

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
#include <ctime>
#include <chrono>


long current_milliseconds() {
auto now = std::chrono::system_clock::now();
return std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
}

// 并不能获取系统时间
long current_milliseconds_v2() {
auto now = std::chrono::steady_clock::now();
return std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
}

long current_milliseconds_v3() {
struct timeval now{};
gettimeofday(&now, nullptr);
return now.tv_sec * 1000 + now.tv_usec / 1000;
}

// 用 time 获取时间由性能问题
long current_seconds() {
time_t t;
time(&t);
return (long) t;
}

long duration_milliseconds(std::chrono::time_point<std::chrono::system_clock,
std::chrono::milliseconds> start) {
auto now = std::chrono::system_clock::now();
return std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count();
}

time(..) 获取时间性能有问题

gettimeofday(...)std::chrono::system_clock::now() 相近

格式化时间

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
#include <iomanip>  // std::put_time
#include <sstream>
#include <ctime>
#include <chrono>

std::string now_format(const std::string &f = "%F %T") {
auto now = std::chrono::system_clock::now();
auto now_t = std::chrono::system_clock::to_time_t(now);
std::stringstream ss;
ss << std::put_time(std::localtime(&now_t), f.c_str());
return ss.str();
}

std::string now_format_v2(const std::string &f = "%F %T") {
time_t now;
time(&now);
char s[30];
struct tm *time_info = localtime(&now);
strftime(s, 30, f.c_str(), time_info);
return {s};
}

std::string now_format_v3(const std::string &f = "%F %T") {
std::time_t t = std::time(nullptr);
char buf[100];
std::strftime(buf, sizeof(buf), "%F %T", std::localtime(&t));
return {buf};
}

std::string now_format_v4(const std::string &f = "%F %T") {
std::time_t t = std::time(nullptr);
std::stringstream ss;
ss << std::put_time(std::localtime(&t), f.c_str());
return ss.str();
}

计算时间差

1
2
3
4
5
6
7
8
9
template <
class result_t = std::chrono::milliseconds,
class clock_t = std::chrono::steady_clock,
class duration_t = std::chrono::milliseconds
>
auto since(std::chrono::time_point<clock_t, duration_t> const& start)
{
return std::chrono::duration_cast<result_t>(clock_t::now() - start);
}

Timer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
template <class DT = std::chrono::milliseconds,
class ClockT = std::chrono::steady_clock>
class Timer
{
using timep_t = typename ClockT::time_point;
timep_t _start = ClockT::now(), _end = {};

public:
void tick() {
_end = timep_t{};
_start = ClockT::now();
}

void tock() { _end = ClockT::now(); }

template <class T = DT>
auto duration() const {
gsl_Expects(_end != timep_t{} && "toc before reporting");
return std::chrono::duration_cast<T>(_end - _start);
}
};

参考这里

使用

1
2
3
4
5
6
7
Timer clock; // Timer<milliseconds, steady_clock>

clock.tick();
/* code you want to measure */
clock.tock();

cout << "Run time = " << clock.duration().count() << " ms\n";

thread & mutex

thread

1
2
std::thread t(func, params...);
t.join();

sleep

1
2
3
4
5
#include "thread"
std::this_thread::sleep_for(std::chrono::milliseconds(1000));

#include <unistd.h>
usleep(microseconds);
1
2
3
4
5
6
#include "thread"
#include "chrono"

using namespace std::chrono_literals;

std::this_thread::sleep_for(20s);

mutex

mutex

1
2
3
4
5
6
7
#include <mutex>

std::mutex mtx;
mtx.lock();
mtx.unlock();

std::lock_guard g(mtx);

std::lock_guard 和 mtx.lock()、mtx.unlock() 作用等同,初始化时上锁,析构时解锁

shared_mutex

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <shared_mutex>

std::shared_mutex mtx;

## 独享锁
mtx.lock();
mtx.try_lock();
mtx.unlock();
# 或者
std::unique_lock lock(mtx);

## 共享锁
mtx.lock_shared();
mtx.try_lock_shared();
mtx.unlock_shared();
# 或者
std::shared_lock lock(mtx);

condition

condition 通常和 mutex 一起使用。

1
2
3
4
5
#include <condition_variable>
std::condition_variable cv;

cv.wait(lock);
cv.notify_one();

下面是一个阻塞队列的示例。

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
namespace ctd {
template<typename T>
class BlockingQueue {
int count;
std::mutex mutex;
std::condition_variable cv;
std::deque<T> data;
public:
void Push(T const &value) {
{
std::unique_lock lock(mutex);
data.push_front(value);
}
cv.notify_one();
}

T Pop() {
std::unique_lock lock(mutex);
cv.wait(lock, [=] { return !this->data.empty(); });
T r(std::move(this->data.back()));
this->data.pop_back();
return r;
}
};
}

特殊函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 默认构造函数
classname ()
// 非默认函数
explicit classname(type param)
// 拷贝构造函数
classname(const classname &other)
// 赋值构造
classname& operator=(const classname &other)
// move 构造
classname(classname &&other)
// 赋值 move 构造
classname& operator=(classname &&other)

// 析构函数
~classname()
Function syntax for class MyClass
Default constructor MyClass();
Copy constructor MyClass(const MyClass& other);
Move constructor MyClass(MyClass&& other) noexcept;
Copy assignment operator MyClass& operator=(const MyClass& other);
Move assignment operator MyClass& operator=(MyClass&& other) noexcept;
Destructor ~MyClass();

默认添加构造函数

判断类型是否有默认构造函数

1
std::cout << std::is_nothrow_move_constructible<Metric>() << std::endl;

不添加默认构造函数

某些会导致编译器不会添加默认构造函数。

1
2
3
4
5
6
7
8
class Metric {
std::map<std::string, int> metrics;
} // OK

class Metric {
std::map<std::string, int> metrics;
std::mutex mtx;
} // not ok

string_view

1
2
3
4
#include <string_view>
using namespace std::literals;

std::string_view v = "hello"sv;

类定义

静态变量

1
2
3
4
5
6
7
8
// a.h
class A {
public:
static int v;
}

// a.cpp
int A::v;

thread_local

静态成员变量定义

1
2
3
4
5
6
7
8
// a.h
class A {
public:
static thread_local int v;
}

// a.cpp
thread_local int A::v;

全局成员定义

函数

仅在 header file

1
2
3
4
5
6
7
// global.h
namespace global {
// static functions
static void f() {
// do something
}
}

header / source 分开定义

1
2
3
4
5
6
7
8
9
10
11
// global.h
namespace global {
static void f();
}

// global.cpp
namespace global {
void f() {
// do something
}
}

特殊语法

template …

Parameter pack

1
2
template<typename T, T...Ts>
class ... {};

this->template

参考这里

文件及目录

当前文件夹

1
2
3
char cwd[512];
getcwd(cwd, 512);
std::cout << cwd << std::endl;

读取文件

1
2
3
4
5
6
7
8
9
10
11
#include <fstream>

std::ifstream file(FILENAME);
if (file.is_open()) {
std::string line;
while (std::getline(file, line)) {
// using printf() in all tests for consistency
printf("%s", line.c_str());
}
file.close();
}

读取整个文件到 string

更多参考 这里

1
2
3
4
5
6
7
8
9
10
11
12
#include <fstream>
#include <iostream>
#include <sstream> //std::stringstream

std::ifstream ins("file.name", std::ios::in | std::ios::binary);
std::string result;
if (ins) {
std::ostringstream contents;
contents << in.rdbuf();
in.close();
result = contents.str();
}