infusion介绍
没啥价值了,不用看了。可以用clang-tidy cpplint等开源的工具
没啥价值了,不用看了。可以用clang-tidy cpplint等开源的工具
;最大句柄数
fs.file-max = 99999
;time_wait状态的socket重新用于新的tcp链接
net.ipv4.tcp_tw_reuse = 1
;tcp发送keeptime的时间,调小可以快速清除无效连接(?单位是什么)
net.ipv4.tcp_keepalive_time = 600
;服务器主动关闭保持FIN_WAIT_2的最大时间
net.ipv4.tcp_fin_timeout = 30
;TIME_WAIT的socket最大值,上限,超过这个值会清掉所有TIME_WAIT TIME_WAIT过多会卡
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.ip_local_port_range = 1024 61000
net.ipv4.tcp_rmem = 4096 32768 262142
net.ipv4.tcp_wmem = 4096 32768 262142
;内核处理接收包队列的长度上限
net.core.netdev_max_backlog = 8096
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.core.rmem_max = 2097152
net.core.wmem_max = 2097152
;tcp syn攻击
net.ipv4.tcp_syncookies =1
;正在三次握手建立阶段的请求队列,可以调高以免丢失客户端连接
net.ipv4.tcp_max_syn.backlog = 1024
滑动窗口大小与套接字缓存设置会在一定程度上影响并发 每个tcp链接都会为了维护滑动窗口而消耗内存
命令行相关
快速退出进程
kill -s SIGTERM <pid>
kill -s SIGINT <pid>
优雅退出
kill -s SIGQUIT <master pid>
kill -s SIGWINCH <worker pid>
重读配置
kill -s SIGHUP <master pid>
日志回滚
kill -s SIGUSR1 <master pid>
还真有这么实现日志回滚的。。。我惊了
平滑升级
kill -s SIGUSR2 <master pid>
这些是对信号的handler做自定义了
通用的ngx_module_t
TCP_DEFER_ACCEPT以及post_accept_timeout 如果连接很久没事件就踢掉
ngx_cycle_t
void ****conf_ctx
所有模块配置项结构体指针(数组->指针->指针数组->指针)讲了很多模块知识。。我对模块不太感兴趣。不看了先
这篇就是参考链接2的总结,还是从参考链接1中单独拎出来说一下
之前学std::variant 和 std::visit 学到了overloaded这个模板,
#include <variant>
#include <cstdio>
#include <vector>
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; }; // (1)
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>; // (2)
using var_t = std::variant<int, const char*>;
int main() {
std::vector<var_t> vars = {1, 2, "Hello, World!"};
for (auto& v : vars) {
std::visit(overloaded { // (3)
[](int i) { printf("%d\n", i); },
[](const char* str) { puts(str); }
}, v);
}
return 0;
}
(2)是c++17引入的新特性,乍一看看不懂,咱们一点一点顺一下
首先,这个overloaded模板就是一个转发继承而来的operator (), 一个粗暴的版本,需要基类实现operator()
struct PrintInt { //(1)
void operator() (int i) {
printf("%d\n", i);
}
};
struct PrintCString { // (2)
void operator () (const char* str) {
puts(str);
}
};
struct Print : PrintInt, PrintCString { // (3)
using PrintInt::operator();
using PrintCString::operator();
};
如果写成模板形式,那就是
template <class... Ts> // (1)
struct Print : Ts... {
using Ts::operator()...;
};
int main() {
std::vector<var_t> vars = {1, 2, "Hello, World!"};
for (auto& v : vars) {
std::visit(Print<PrintCString, PrintInt>{}, v); // (2)
}
return 0;
}
注意到这个写法特别重,考虑到开头这个优雅的用法,使用lambda,代码写起来就更难看了
int main() {
std::vector<var_t> vars = {1, 2, "Hello, World!"};
auto PrintInt = [](int i) { printf("%d\n", i); }; // (1)
auto PrintCString = [](const char* str) { puts(str); };
for (auto& v : vars) {
std::visit(
Print<decltype(PrintCString), decltype(PrintInt)>{PrintCString, PrintInt}, // (2)
v);
}
return 0;
}
所以理所当然,推导动作应该放在一个helper函数里, 上面这个调用模式还是很容写出一个推导helper的
template <class... Ts> // (1)
auto MakePrint(Ts... ts) {
return Print<Ts...>{ts...};
}
int main() {
std::vector<var_t> vars = {1, 2, "Hello, World!"};
for (auto& v : vars) {
std::visit(
MakePrint( // (2)
[](const char* str) { puts(str); },
[](int i) { printf("%d\n", i); }
),
v);
}
return 0;
}
这已经和overload非常接近了,回到一开始我们提到的,如何写成开头那个样子呢,这就需要c++
17 的新特性,类模板实参推导, 自定义推导指引,User-defined deduction guides,简单说,就是构造函数能做helper的活(make_tuple, make_pair),只要定义好规则就可以
在c++17中,可以干净的写出
std::tuple t(4, 3, 2.5); // same as auto t = std::make_tuple(4, 3, 2.5);
在tuple中,写好了推导规则
#ifndef _LIBCPP_HAS_NO_DEDUCTION_GUIDES
// NOTE: These are not yet standardized, but are required to simulate the
// implicit deduction guide that should be generated had libc++ declared the
// tuple-like constructors "correctly"
template <class _Alloc, class ..._Args>
tuple(allocator_arg_t, const _Alloc&, tuple<_Args...> const&) -> tuple<_Args...>;
template <class _Alloc, class ..._Args>
tuple(allocator_arg_t, const _Alloc&, tuple<_Args...>&&) -> tuple<_Args...>;
#endif
make_tuple就下岗了
类似的,只要为Print写好推导,就可以省掉MakePrint
#include <variant>
#include <cstdio>
#include <vector>
using var_t = std::variant<int, const char*>;
template <class... Ts>
struct Print : Ts... {
using Ts::operator()...;
};
template <class...Ts> Print(Ts...) -> Print<Ts...>; // (1)
int main() {
std::vector<var_t> vars = {1, 2, "Hello, World!"};
for (auto& v : vars) {
std::visit(
Print{ // (2)
[](const char* str) { puts(str); },
[](int i) { printf("%d\n", i); }
},
v);
}
return 0;
}
到此,overloaded trick就解释完了
对overload的解释 https://dev.to/tmr232/that-overloaded-trick-overloading-lambdas-in-c17
对overload的解释和加强,并且有提案。https://arne-mertz.de/2018/05/overload-build-a-variant-visitor-on-the-fly/
类模板实参推导 https://zh.cppreference.com/w/cpp/language/class_template_argument_deduction 注意后面的User-defined deduction guides 用户定义推导指引
这篇文章更好的写了个match,我没写成。。这个写的还挺好玩的https://zhuanlan.zhihu.com/p/52519126
因为rust的enum让我回想起union和 variant,决定找找文档仔细说一下这个variant,做个笔记
std::variant是c++17加入的新容器,主要就是safe union。用来和enum比较也算合适,都叫做sum type,类型是线程(求和)的,只表现出线性数目的类别实例,product type是乘积的(比如结构体),这个是函数式概念了,先做个科普
下面是一个std::visit+ std::variant的例子,同比rust中的enum match
std::variant<double, bool, std::string> var;
struct {
void operator()(int) { std::cout << "int!\n"; }
void operator()(std::string const&) { std::cout << "string!\n"; }
} visitor;
std::visit(visitor, var);
#![allow(unused_variables)]
fn main() {
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
}
差距还好。rust也可以直接调用函数 lambda。对比来说,c++需要手动写visitor有点难看。有没有make_visitor呢
overload
下面的链接有make_visitor, 就是这个overload,在cpp reference std::visit的示例中,也有使用overload这个模板,长这个样子
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
于是,上面的代码就变成这样
std::variant<double, bool, std::string> var;
std::visit(overloaded {
[](auto arg) { std::cout << arg << ' '; },
[](double arg) { std::cout << std::fixed << arg << ' '; },
[](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
}, var);
感觉稍微干净了点是不是?手写operator()还是有点难受的?换成lambda只能写一个,也得用overload包装一下
overload原理就是模板推导和转发,变参模板可能看不懂,写成一个继承的就容易明白了
struct overloadInt{
void operator(int arg){
std::cout<<arg<<' ';
}
};
struct overload : overloadInt{
using overloadInt::operator();
};
不用std::visit行不行
行,又要走SFINAE 老路了,enable_if 糊一个,还要判断variant里到底存了什么,基本上和visit差不多?我糊了半天糊出个这么个玩意儿。
#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>
template<typename T, typename VARIANT_T>
struct is_variant_member_type;
template<typename T, typename... Ts>
struct is_variant_member_type<T, std::variant<Ts...>>
: public std::disjunction<std::is_same<T, Ts>...> {};
template <typename V > typename std::enable_if<is_variant_member_type<std::string,V>::value&&
is_variant_member_type<double,V>::value>&&
is_variant_member_type<int,V>::value>::type
match (V v)
{
if (std::holds_alternative<int>(v))
std::cout << std::get<int>(v) << ' ';
if (std::holds_alternative<std::string>(v))
std::cout << std::quoted(std::get<std::string>(v)) << ' ';
if (std::holds_alternative<double>(v))
std::cout<<std::fixed << std::get<double>(v) << ' ';
}
// the variant to visit
using var_t = std::variant<int, double, std::string>;
int main() {
std::vector<var_t> vec = {10, 15l, 1.5, "hello"};
for(auto& v: vec) {
match(v);
}
}
注意,用if-constexpr不可以,虽然std::holds_alternative是constexpr的。。暂时没搞懂
感觉吧match拆一拆,拆成lambda类似形式的,可以结合overload。这个写的用不用enable_if没什么区别。。我以后再写吧。。这里学的不明白。
笔记,两本书的记录,不值得看。以前记在印象笔记的,搬迁出来做个记录
记录一些零碎的c的东西
https://stackoverflow.com/questions/18330673/bzero-bcopy-versus-memset-memcpy
简而言之 bzero相当于memset bcopy相当于mommove
// void bzero(void *s, size_t n);
#define bzero(s, n) memset((s), 0, (n))
// void bcopy(const void *s1, void *s2, size_t n);
#define bcopy(s1, s2, n) memmove((s2), (s1), (n))
https://stackoverflow.com/questions/1201319/what-is-the-difference-between-memmove-and-memcpy
区别在于src和dst可不可以重叠
strcasecmp
一个常见的比较字符串的需求,不分大小写
在linux上可以用strcasecmp,在windows上可以用stricmp,需要写个宏糊到一起,当然,也有其他办法,参考链接给出了很多种实现
比如下面这个不怎么费力的
#include <algorithm>
bool iequals(const string& a, const string& b)
{
return std::equal(a.begin(), a.end(),
b.begin(), b.end(),
[](char a, char b) {
return tolower(a) == tolower(b);
});
}
或者boost::iequals,这个是怎么实现的?
//! 'Equals' predicate ( case insensitive )
/*!
This predicate holds when the test container is equal to the
input container i.e. all elements in both containers are same.
Elements are compared case insensitively.
\param Input An input sequence
\param Test A test sequence
\param Loc A locale used for case insensitive comparison
\return The result of the test
\note This is a two-way version of \c std::equal algorithm
\note This function provides the strong exception-safety guarantee
*/
template<typename Range1T, typename Range2T>
inline bool iequals(
const Range1T& Input,
const Range2T& Test,
const std::locale& Loc=std::locale())
{
return ::boost::algorithm::equals(Input, Test, is_iequal(Loc));
}
#define offsetof(a,b) ((int)(&(((a*)(0))->b)))
#define offsetof(struct_t,member) ((size_t)(char *)&((struct_t *)0)->member)
(struct_t *)0是一个指向struct_t类型的指针,其指针值为 0,所以其作用就是把从地址 0 开始的存储空间映射为一个 struct_t 类型的对象。((struct_t *)0)->member 是访问类型中的成员 member,相应地 &((struct_t *)0)->member) 就是返回这个成员的地址。由于对象的起始地址为 0,所以成员的地址其实就是相对于对象首地址的成员的偏移地址。然后在通过类型转换,转换为 size_t 类型(size_t一般是无符号整数)。
所以,offsetoff(struct_t,member)宏的作用就是获得成员member在类型struct_t中的偏移量。
对实时嵌入式系统,MISRA–作为工业标准的C编程规范的Rule 120 禁止使用offsetof.
Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址。
Container_of的定义如下:
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
其实它的语法很简单,只是一些指针的灵活应用,它分两步:
第一步,首先定义一个临时的数据类型(通过typeof( ((type *)0)->member )获得)与ptr相同的指针变量__mptr,然后用它来保存ptr的值。
第二步,用(char *)__mptr减去member在结构体中的偏移量,得到的值就是整个结构体变量的首地址(整个宏的返回值就是这个首地址)。
push src 等同于esp <- esp -4, [esp] <-src更新栈指针,保存值
pop dst 等同于 dst <- [esp], esp+4; 取出值,更新栈指针
move dst src 好懂,可能at&t的汇编风格和Intel的汇编风格不一致
leave 等同于move esp, ebp ;pop ebp
call src 相当于push eip eip <- src 保存旧的eip, 把src赋给eip更新成新的作用域
ret就相当于pop eip
struct tcphdr
{
u_int16_t th_sport; /* source port */
u_int16_t th_dport; /* destination port */
tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */
# if __BYTE_ORDER == __LITTLE_ENDIAN
u_int8_t th_x2:4; /* (unused) */
u_int8_t th_off:4; /* data offset */
# endif
# if __BYTE_ORDER == __BIG_ENDIAN
u_int8_t th_off:4; /* data offset */
u_int8_t th_x2:4; /* (unused) */
# endif
u_int8_t th_flags;
# define TH_FIN 0x01
# define TH_SYN 0x02
# define TH_RST 0x04
# define TH_PUSH 0x08
# define TH_ACK 0x10
# define TH_URG 0x20
u_int16_t th_win; /* window */
u_int16_t th_sum; /* checksum */
u_int16_t th_urp; /* urgent pointer */
};
localtime不可重入 https://stackoverflow.com/questions/35806261/how-to-use-mktime-without-changing-the-original-tm-struct
如果对同一个结构体指针调用两次,会返回同一个结果,不管你的指针如何改动,使用localtime_r 或者别用这个傻逼函数
c23 localtime_r进了标准,各个平台都会实现,没有兼容性问题
gdb汇总
作者是Jonathan Boccara, Fluent C++作者,这个PPT就是卖书的
大纲
如果darknet要支持GPU和CUDNN的话,会有很多坑。
安装CUDA 两种方式,下载安装包和安装软件源
具体在https://developer.nvidia.com/cuda-downloads
我选的是网络安装deb
首先要下载deb文件,然后执行上面的步骤,cuda 就安装好了,默认在环境变量内。不用修改Makefile
如果是手动安装软件包,需要改动makefile
COMMON需要改正安装的路径 安装结束后,需要注意修改nvcc路径,不在环境变量中可能会识别不到,改下路径
安装CUDNN
这个没有办法,不能用命令行
https://developer.nvidia.com/rdp/cudnn-download
点第一个就可以(需要注册)
tar -zxvf cudnn-9.2-linux-x64-v7.1.tgz
cp cuda/include/cudnn.h /usr/local/cuda/include/
cp cuda/lib64/* /usr/local/cuda/lib64/
然后编译就可以了