0%

C++11 之后 enum 的新增功能

enum class 是 C++11 提供的功能,为了更好理解后文的内容,我们先看看 C++11 之后 enum 有什么变化。参考资料见 https://en.cppreference.com/w/cpp/language/enum

有作用域枚举

有作用域枚举(Scoped enumerations)使用 enum class|struct ClassName 声明,以区别于原来的无作用域枚举。无作用域枚举的枚举量可以直接在外围名字空间中访问,当枚举类有名字且 C++ 版本至少为 C++11 时,可以通过 枚举名::枚举量 访问;有作用域枚举只能通过 枚举名::枚举量 访问。

有作用域枚举的默认底层类型是 int

例子:

void example() {
    enum class Color { red, green = 20, blue };
    Color r = Color::blue;
}

我的理解

CUDA 的 API 都是和 device 相关的,调用前要先确保已经调用过 cudaSetDevice 将 context 关联到相关的设备上(据 Stackoverflow 的老提问,这个 context 会占用 150 MB 显存;从我这边来看,这个显存占用量还更大一些,有 200300 MB)。创建流是不需要提供设备号的,所以它肯定使用的是 thread_local 的 device。

也就是说,每个流是和设备关联起来的,用 cudaDeviceSynchronize 实际上是同步了这个设备上所有的流,而 cudaStreamSynchronize 是同步了单个流。前者的同步范围更大

根据 Stackoverflow 的这个回答cudaStreamSynchronize 的默认参数是 nullptr,也就是默认流,同步它相当于同步当前设备上的所有阻塞流。由于可以创建非阻塞流,所以就算不给 cudaStreamSynchronize 传参或者传 nullptr,效果也和 cudaDeviceSynchronize() 可能是不一样的。

cudaStreamCreateWithFlags( stream_0, cudaStreamNonBlocking );
cudaStreamCreate( stream_1 );
// ...
cudaStreamSynchronize( nullptr ); // sync with stream_1 and legacy stream
cudaDeviceSynchronize(); // sync with stream_0, stream_1 and legacy

其他

cudaThreadSynchronize 方法和 cudaDeviceSynchronize 很相似,前者是过时方法,建议使用后者。

经过

遇到过一个坑:为共享库写函数,但是又需要从头文件隐藏实现时,不要将函数声明为内联。否则编译器会认为它未被使用并忽略它,链接的时候就找不到这个函数。

项目使用的语言是 C++。

TL;DR

其实只是不会主动生成函数定义罢了,不是不能对外链接。除非调用处看到的声明带有 inline 关键字,从而尝试在其所在的翻译单元中寻找。

尝试解释:C++ 中内联函数按需生成

https://zh.cppreference.com/w/cpp/language/inline 中有一句:

内联函数或变量 (C++17 起) 的定义必须在访问它的翻译单元中可达(不一定要在访问点前)。

Gitlab 极狐版本是极狐购买了经营权的版本,内部也分会员版。从免费版的功能来看,两者几乎没有区别。但是为了更严谨一些,本博客中所有内容都可能是在 gitlab-jh 或者 gitlab-ce 上试过(或者混用),不保证仅在 gitlab-ce 上操作(尽管它们的操作方式应该一致)。

问题简述

主机 A 有自己的内网服务,用的是 Gitlab Premium。主机 B 也有自己的内网服务,用的是 Gitlab 极狐(而且是免费版)。目前仓库是在 B 上的,需要在 A 上创建镜像仓库。

分析

由于主机 A 是付费服务支持功能更多,所以我选择由主机 A 主动拉取(Pull) B 的仓库。

过程

首先在 A 上面创建空仓库,然后点进去选择 Settings > Repository > Mirroring repositories,在下面填入仓库的 URL。我们的主机 B 只把 http 端口映射出来了,也没有映射出来 ssh 端口,所以不能使用公钥验证,而只能选择密码验证,URL 的协议也只能是 http(我们仓库没做 https)。

注意以下几点(这三个坑我都踩过):

先说解决方案

参考 Networking problems with WSL2 and Docker Desktop for windows,编辑 /etc/docker/daemon.json,加入 "bip": "192.168.200.1/24"(根据实际情况替换),然后 systemctl 重载配置、重启 Docker 一通操作后用 ip routeifconfig 验证一下变化。

为什么会有这个需求

WSL2 的网段是 172.17 开头的,这恰好和 Docker 的默认网段撞了,导致 Docker 不能直接使用 WSL2 的网关 ip 前缀的系统代理(会被认为是 Docker 内部的网址)。每次都要根据 Windows 实际的局域网 ip 来写 http 代理,太麻烦了。修改 Docker 网段之后就可以继续使用系统代理(虽然还是得传递,但是可以直接在命令行上写 --build-arg HTTP_PROXY=$http_proxy --build-arg HTTPS_PROXY=$http_proxy 之类)。另外,由于网络代理请求是统一从 WSL2 的网关发起的,只需要在 Clash for Windows 中设置 inbounds 就能仅允许这些连接请求,这样就不必冒着裸奔的风险开启局域网内代理了。

inbounds:
  - "http://172.17.xxx.yyy:zzz"

相关文章

Clash for Windows 相关

参考

https://joellaity.com/2020/01/31/string.html

std::stringstd::basic_string<> 的一个特化,该类的 value_type 是 char。本文虽然是讨论 std::basic_string<> 的实现方式,但是为了方便,假设 value_typechar、假设目标平台是 64 位,讨论时也将把 std::basic_string<>std::string 互用。

libstdc++

libstdc++ 是 gcc 所用的标准库实现,也是 clang 在不提供 -stdlib=... 选项下的默认标准库实现。在 64 位环境下,libstdc++ 中的 std::string 占用 32 个字节。

Tip

std::vector<> 的大小(std::vector<bool> 有特化,所以是例外,在 测试 看到 libstdc++ 和 libc++ 中 std::vector<bool> 的大小分别是 40 和 24 字节)是 24 字节,因为它也需要 capacity + size + pointer 三元组。

std::string 把 capacity + size + pointer 三元组的 capacity 改成了 buffer 和 capacity 的联合体,其中 buffer 大小为 16 字节,可以容纳除去 \0 的 15 个字符。当 size 小于等于临界值时,联合体存储的就是 buffer,否则是 capacity。

我在做什么?

你想要最终达成什么(目标)?你采用了什么样的路径来达成它(途径)?

Tip

有可能你的目标是不现实的,或者是假想出来的替代目标,换一个目标同样能解决你的困难,但是解决起来容易很多。也可能你的路径是有错误的。

例子:我希望调用接口 A 来加载目录 B 下的所有图片,供程序的其他组件使用。

预期结果

按照你的理解,你觉得代码或者软件配置应该引发什么行为?

例子:调用接口从目录下加载得到的图片数量和目录下的真实图片数量相等,有 14 张图片就应该得到 1 个长度为 14 的图片数据的向量。

资源

可用 Docker Hub 镜像加速器列表见 Docker Hub 镜像加速器

修改方式

网络上有不少教程是先修改 /etc/docker/daemon.json,然后:

sudo systemctl daemon-reload
sudo systemctl restart docker

但是这样需要重启 Docker。虽然可以先给 Docker 加上 live-store 属性,但是我也不敢冒这个风险。

查了相关资料之后我发现:让 docker 重新加载配置只需要向其发送一个信号。如果是用 systemctl 管理 docker,可以直接这样做(参考这篇文章):