c++ Memory Order
std::thread 注意事项
join
和 detach
join
或者detach
只能调用一次当调用
join
或者detach
之后会将持有的线程ID置为0
, 再次调用会抛异常。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
29void
thread::join()
{
int ec = EINVAL;
if (!__libcpp_thread_isnull(&__t_))
{
ec = __libcpp_thread_join(&__t_);
if (ec == 0)
__t_ = _LIBCPP_NULL_THREAD;
}
if (ec)
__throw_system_error(ec, "thread::join failed");
}
void
thread::detach()
{
int ec = EINVAL;
if (!__libcpp_thread_isnull(&__t_))
{
ec = __libcpp_thread_detach(&__t_);
if (ec == 0)
__t_ = _LIBCPP_NULL_THREAD;
}
if (ec)
__throw_system_error(ec, "thread::detach failed");
}
CSS Layout
本文字数: 40 阅读时长 ≈ 1 分钟
mongodb 入门-Aggregate
mongodb 入门-CRUD
文档主键
文档主键 _id
文档主键 _id
是每篇文档必备的字段,具有以下特性:
- 文档主键的唯一性
- 支持所有数据类型(数组除外)
- 复合主键
对象主键 ObjectId
当我们不提供主键,MongoDB
自动为我们生成的默认对象主键 ObjectId
- 默认的文档主键
- 可以快速生成的
12
字节id
- 包含创建时间
ObjectId
默认值
1 | test> ObjectId() |
手动设置 ObjectId
的值
1 | test> ObjectId("123456789011123456789011") |
提取 ObjectId
的创建时间
1 | test> ObjectId("123456789011123456789011").getTimestamp() |
mongodb 入门-索引
索引
- 对文档部分内容进行排序的数据结构
- 加快文档查询和文档排序的速度
- 复合键索引只能支持前缀子查询
索引操作
创建索引
1 | db.<collection>.createIndex(<keys>, <options>) |
<keys>
文档指定了创建索引的字段<options>
创建索引的参数和设定索引的特性
创建一个单键索引
1 | db.accountWithIndex.createIndex({name: 1}) |
创建一个复合键索引
1 | db.accountWithIndex.createIndex({name: 1, balance: -1}) |
创建一个多键索引,创建在数组字段上, 数组字段中的每一个元素都会在多键索引中创建一个键
1 | db.accountWithIndex.createIndex({currency: 1}) |
列出集合中的索引
1 | db.accountWithIndex.getIndexes() |
@executable path, @load path 和 @rpath
在 macOS
上,动态链接器使用特定的路径变量来解析运行时的库位置。这些路径变量包括:绝对路径、 @executable_path
、@loader_path
和 @rpath
。
绝对路径
对于安装在系统中共享位置的框架很有用,一般是 /Library/Frameworks/xxx
、 /usr/lib/xxx
, 但是查找嵌入在应用内部的动态库就很难使用,应用安装的位置都不固定,所以引出新的方式。
@executable path
@executable_path
是用于指代当前正在执行的程序或应用的路径。当你的应用程序或其动态库需要引用位于与可执行文件相同路径(或其子目录)下的其他动态库时,这会非常有用。
libevent 使用入门
概述
libEvent
, 一个事件通知库。有以下特点:
- 事件驱动,高性能;
- 轻量级,专注于网络;
- 跨平台,支持
Windows
、Linux
、Mac
等; - 支持多种
I/O
多路复用技术,epoll
、poll
、dev/poll
、select
和kqueue
等; - 支持
I/O
,定时器和信号等事件;
libevent接口分析
libevent 接口大概分为以下几类:
- 环境配置和初始化
event_base_new
evutil socket
函数封装evutil_make_socket_nonblocking
evutil_make_listen_socket_reuseable
- set SO_REUSEADDR on Unix and does nothing on Windows
evutil_closesocket
- 事件
IO
处理event_new
- 缓冲
IO
bufferevent
- 循环(
Loop
)event_base_dispatch
Libevent API
libevent上下文创建
- event_base *event_base_new(void)
- event_base *event_base_new_with_config( const struct event_config *);
- 配置参数
- event_config *event_config_new(void);
- void event_config_free(struct event_config * cfg);
- 配置参数
- event_reinit
- int event_reinit(struct event_base *base); 调用 fork 之后可以正确工作
- void event_base_free(struct event_base *); 释放event_base内部分配的空间及其本身对象的空间,不释放事件和socket和在回调函数中申请 的空间
- event_config_set_flag
- event_config_avoid_method(struct event_ config *cfg, const char *method);
- event_config_require_features
event_base_config_flag
EVENT_BASE_FLAG_NOLOCK:
- 不要为event_base 分配锁。设置这个选项可以为event_base 节省一点用于锁定和解锁的时间,但是让在多个线程中访问event_base 成为不安全的。
EVENT_BASE_FLAG_IGNORE_ENV
- 选择使用的后端时,不要检测EVENT_*环境变量。使用这个标志需要三思:这会让用户更难 调试你的程序与libevent 的交互。
EVENT_BASE_FLAG_STARTUP_IOCP
- 仅用于Windows,启用任何必需的IOCP 分发逻辑
- iocp
- event_config_set_num_cpus_hint
- event_config_set_flag(cfg, EVENT_BASE_ FLAG_STARTUP_IOCP)
- evthread_use_windows_threads();
EVENT_BASE_FLAG_NO_CACHE_TIME
- 不是在事件循环每次准备执行超时回调时检测当前时间,而是在每次超时回调后进行检 测。注意:这会消耗更多的CPU 时间。
EVENT_BASE_FLAG_EPOLL_USE_ CHANGELIST
- epoll下有效,防止同一个fd多次激发事件,fd如果做复制会有bug
EVENT_BASE_FLAG_PRECISE_TIMER
- 默认使用系统最快的记时机制,如果系统有较慢 且更精确的则采用
event_method_feature
- EV_FEATURE_ET = 0x01
- 边沿触发的后端
- EV_FEATURE_O1 = 0x02,
- 要求添加、删除单个事件,或者确定哪个事件激 活的操作是O(1)复杂度的后端
- EV_FEATURE_FDS = 0x04,
- 要求支持任意文件描述符,而不仅仅是套接字的 后端
- EV_FEATURE_EARLY_CLOSE = 0x08
- 检测连接关闭事件。您可以使用它来检测连接何时关闭,而不必从连接中读取所有挂起的数据。 并非所有后端都支持EV_CLOSED。允许您使用EV_CLOSED,而不需要读取所有挂起的数据。无法在所有内核版本上
事件Event处理
循环(loop)
缓冲 bufferevent
libevent http
I/O 多路复用
select
select
实现多路复用的方式是,将已连接的 socket
都放到一个文件描述符集合,然后调用 select
函数将文件描述符集合拷贝到内核里,让内核来检查是否有网络事件产生,通过遍历文件描述符集合的方式,当检查到有事件产生后,将此 socket
标记为可读或可写, 接着再把整个文件描述符集合拷贝回用户态里,然后用户态还需要再通过遍历的方法找到可读或可写的 socket
,然后再对其处理。
所以,对于 select
这种方式,需要进行 2 次「遍历」文件描述符集合,一次是在内核态里,一个次是在用户态里 ,而且还会发生 2 次「拷贝」文件描述符集合,先从用户空间传入内核空间,由内核修改后,再传出到用户空间中。
select 函数原型
1 | #include <sys/select.h> |
- 返回值
- 若有就绪描述符则为其数目,若超时则为
0
,若出错则为-1
- 若有就绪描述符则为其数目,若超时则为
- 参数
maxfd
: 待测试的描述符基数,它的值是待测试的最大描述符加1
readfds
:读描述符集合writefds
:写描述符集合errorfds
:异常描述符集合timeout
: 超时设置