Типичная разработка на С++
или
Как я диагностировал множественные прострелы ног
Василий Шестак, Imagine Software
vass@ciklum.com
Распределение знаний типичного программиста на С++
«Типичная разработка на С++: вы решаете проблемы, которые создает ваш же инструмент.»� Anonymous
«При помощи C вы легко можете выстрелить себе в ногу. При помощи C++ это сделать сложнее, но если это произойдёт, вам оторвёт всю ногу целиком.» � Bjarne Stroustrup
2
Не мешайте fork() и потоки
3
Не мешайте fork() и потоки
4
Не мешайте fork() и потоки
5
Перегрузка небезопасных функций
6
/**
* Guards the given fork-unsafe function to make forking safer.
* If itsAboutToFork flag set, function stops all the threads which try to execute fork-unsafe function
*/
template <typename… Ts, typename F>
auto invokeForkUnsafeFunction(F* func, Ts… args) noexcept
{
UnsafeFunctionTracker guard;
return func(args…);
}
/**
* Shadows the localtime_r glibc function to make forking safer.
* If itsAboutToFork flag set, function stops all the threads which try to execute localtime_r.
*/
tm* localtime_r(const time_t* clock, tm* res) noexcept
{
using ltr_t = tm* (*)(const time_t*, tm*);� static auto sys_localtime_r = (ltr_t)dlsym(RTLD_NEXT, “localtime_r”);
return invokeForkUnsafeFunction(sys_localtime_r, clock, res);
}
Не мешайте fork() и C++
7
const auto pid = fork();
if (pid == 0)
{
logger().reinit();
logger(log::Info) << “Process started”;
int status = doSomething();
exit(status);
}
Советы
8
* Исключение - fork() + exec()
Как GCC способен заблудиться в двух сегментах
9
Python GDB[1]
10
Преимущества:
Недостатки:
Python GDB
11
def print_var(names):
for name in names:
print name + ‘=’
gdb.execute(‘print’ + name)
gdb.execute(‘info address’ + name)
l = []
l.append(Tracepoint(‘ComplexObject::ComplexObject’, lambda: print_var([‘this’])))
l.append(Tracepoint(‘ComplexObject::~ComplexObject’, lambda: print_var([‘this’])))
l.append(Tracepoint(‘ComplexObject::~ComplexObject’, lambda: print_backtrace))
static и thread_local
mov rax,QWORD PTR ds:0x50� movzx eax,BYTE PTR [rax]� test al,al #check a guard�- jne 0x6e13665�|�|�| mov rdi,QWORD PTR ds:0x58�| call 0x6e138f4<Flag::Flag()> #init�|�|�| mov rax,QWORD PTR ds:0x50�| mov BYTE PTR [rax],0x1 #set a guard�|�->mov rdi,QWORD PTR ds:0x58� call 0x6e164f4<Flag::get()> #use it
mov rax,QWORD PTR fs:0x0� lea rax,[rax-0x28]� movzx eax,BYTE PTR [rax]� test al,al #check a guard�- jne 0x6e13685�| mov rax,QWORD PTR fs:0x0�| lea rax,[rax-0x18]�| mov rdi,rax�| call 0x6e138f4<Flag::Flag()> #init�| mov rax,QWORD PTR fs:0x0�| lea rax,[rax-0x28]�| mov BYTE PTR [rax],0x1 #set a guard�->mov rax,QWORD PTR fs:0x0� lea rax,[rax-0x18]� mov rdi,rax� call 0x6e164f4<Flag::get()> #use it
mov rax,QWORD PTR fs:0x0� mov rax,QWORD PTR ds:0x0� lea rax,[rax-0x28]� movzx eax,BYTE PTR [rax]� test al,al #check a guard�- jne 0x6e13685�| mov rax,QWORD PTR fs:0x0�| lea rax,[rax-0x18]�| mov rdi,rax�| call 0x6e138f4<Flag::Flag()> #init�| mov rax,QWORD PTR fs:0x0�| lea rax,[rax-0x28]�| mov BYTE PTR [rax],0x1 #set a guard�->mov rax,QWORD PTR fs:0x0� lea rax,[rax-0x18]� mov rdi,rax� call 0x6e164f4<Flag::get()> #use it
12
Советы
13
Знай свой компилятор
14
Знай свой компилятор[1]
15
// Деструктор вызван не будет
Наивный lock-free
16
Наивный lock-free
17
Memory reordering
18
mov [_x], 1 |
mov ax, [_y] |
mov ax, [_y] |
mov [_x], 1 |
Thread 0 | Thread 1 |
store(zeroWants, 1) | store(oneWants, 1) |
store(victim, 0) | store(victim, 1) |
r0 = load(oneWants) | r0 = load(zeroWants) |
r1 = load(victim) | r1 = load(victim) |
Thread 0 | Thread 1 |
r0 = load(oneWants) | r0 = load(zeroWants) |
store(zeroWants, 1) | store(oneWants, 1) |
store(victim, 0) | store(victim, 1) |
r1 = load(victim) | r1 = load(victim) |
Наивный lock-free
[1] Microsoft specific volatile behavior
19
Советы
20
Как “ускорить” double?
21
Борьба с ошибками округления
22
Ускорение расчетов
��
23
Вопросы?
Благодарю�за внимание!